Search code examples
jqueryajaxdockernginxmicroservices

URLs containing question marks used in jQuery.ajax change in specific setup (Docker, Nginx rewrite rule)


I have a dockerized PHP/Laravel app that's working fine inside a php:7.4-apache container. We had it routed to http://localhost:81 for development purposes.

Now we want this service to be available at http://localhost/foo/bar in our network of microservices. Request to localhost go to an nginx service, and we've set up a rewrite rule in nginx_cors.conf to achieve this:

location /foo/bar {
  rewrite ^/foo/bar/?(.*) /$1 break;
  proxy_pass http://laravel_app;
}

But now some jQuery.ajax requests fail. This is what happens:

// in vendor code
// url is http://localhost/foo/bar/ajax/lib/?someParam=someValue
$.ajax({
  url: url
});

// in Chrome DevTools
// Note that foo/bar/ is gone
jquery.js:4 GET http://localhost/ajax/lib?someParam=someValue 404 (Not Found)

The problem seems to affect all URLs that contain a question mark. We stripped it for a request that contains no params, and the request went through. But that's not possible in the above case.

What is happening here? I'm not sure if the nginx rewrite rule might be to blame as I wouln't expect the browser to notice it's effect at all (and the above error message is from Chrome DevTools).

edit

Looking at the network tab in Chrome, I realized there are two similar requests:

  • One goes to http://localhost/foo/bar/ajax/lib/?someParam=someValue as expected. nginx responds with a 301 and a location header http://localhost/ajax/lib?someParam=someValue.
  • The second one goes to http://localhost/ajax/lib?someParam=someValue, which is precisely the location header from the first request. Again nginx responds, this time with a 404.

So it seems nginx 'forwards' the first request to itself instead of the Laravel app.


Solution

  • It seems that the redirection from /ajax/lib/ to /ajax/lib issued by the laravel app rather than nginx itself. The default nginx behavior for rewriting the Location header is to substitute the backend hostname/protocol with the request one giving you http://laravel_app/ajax/lib rewrited to http://localhost/ajax/lib. That request wouldn't fall under the location /foo/bar { ... } and would be served by some other nginx location giving you HTTP 404 Not found error. You need to override the default proxy_redirect behavior with the following directive:

    proxy_redirect http://laravel_app/ http://localhost/foo/bar/;