0

I am trying to set up my SPA to return 404 for invalid resources by having nginx do a backcheck for the resource before responding. All this is to avoid invalid pages coming with 200 and thus having spiders crawling soft 404 pages.

My desired behaviour

Browser                           Nginx                           API
  | -- GET myapp.com/users/12 -->   |                              |
  |                                 | -- GET myapi:8000/users/12   |
  |                                 |   <----------- 404 --------  |
  | <-- 404 index.html ------------ |
  |                                 |

I expect my configuration to be something like below

server {
        listen       80;
        server_name  localhost;
        root   /usr/share/nginx/html;
        index  index.html;

        location /users/ {
          # 1. Fetch from myapi:8000
          # 2. Return index.html with status from fetched URI
        }
}

I've been digging around for a while now but I'm a bit lost on how to achieve this. I've seen many simple examples out there with try_files etc. but nothing that seems to fit my case, since it seems most examples do very simplistic forwarding.

How can I achieve the above behaviour?

Pithikos
  • 139
  • 5
  • nginx doesn't have this kind of functionality built-in. Getting status code and response body from separate sources is in strong disagreement of nginx fundamental design. You might be able to hack something with nginx lua module. – Tero Kilkanen May 22 '20 at 19:16
  • @TeroKilkanen thanks for the reply. I tried with Lua but it fastly became too cumbersome. I ended up making my backend API instead to serve the index.html. – Pithikos May 22 '20 at 19:30

1 Answers1

0

I managed to solve this by having my backend API to always respond with index.html for Accept: text/html. I did try the Lua way with OpenResty but it felt too hacky and quirky and too complex to maintain.

Then my config looks like below:

    location / {
      try_files $uri $uri/ @forward_to_api;
    }

    location @forward_to_api {
      rewrite ^(.*) /api$1 break;
      proxy_set_header "Accept" "text/html";
      proxy_pass http://localhost:8000;

      # Follow any redirects
      proxy_intercept_errors on;
      error_page 301 302 307 = @follow_redirect;
    }

    location @follow_redirect {
      set $moved_location $upstream_http_location;
      proxy_pass http://localhost:8000$moved_location;
    }

This will redirect all $uri to localhost:8000/api/$uri and follow redirects.

Pithikos
  • 139
  • 5