Nginx POST request is changed to GET when using Ajax

emma asked:

I have an Nginx server used for a store. That store has an API which is in a different folder for which i’m using an alias. Here is my example.com from sites-enabled in Nginx:

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name www.example.com;

    root /var/www/store/public;

    #certificated go here [edited]

    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name example.com;

    root /var/www/store/public;

    index index.php;

    #certificates go here [edited]

    location /admin {
            index index.php;
    }

    location /api {
            alias /var/www/api/public;
            
            try_files $uri $uri/ @api;

            location ~ \.php$ {
                    include snippets/fastcgi-php.conf;
                    fastcgi_param SCRIPT_FILENAME $request_filename;
                    fastcgi_split_path_info ^(.+\.php)(/.+)$;
                    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
            }
    }

    location @api{
            rewrite /api/(.*)$ /api/index.php?/$1 last;
    }
  
    #the rest of the store config block [edited]

}

The problem that i have is that if i send a POST request using ajax to ‘example.com/api’ it is changed to a GET and all the parameters are lost.

Here is my Ajax code:

var foo = 'foo';
var bar = 'bar';

$.ajax({
    type: 'POST',

    beforeSend: function(request) {
        request.setRequestHeader("Authorization", 'xyz');
    },
    url: "https://example.com/api",
    data: { foo: foo, bar: bar},
    processData: false,
    success: function(data) {
        console.log(data);
    }
});

To test this i simply dumped $_SERVER['REQUEST_METHOD'].

If i call for example.com/api/index.php the request type is as it should be POST but if i call just example.com/api it is changed to GET.

How can i preserve the request type and parameters for a request?

My answer:


Your use of a location @api and a rewrite doesn’t make much sense here. As it stands, your requests have to get processed through three different location blocks before they are finally sent upstream to PHP.. It is also reversed from the normal pattern I would expect to see.

It looks like the request is getting mangled by the automated 301 redirect from /api to /api/ that web servers always apply to paths that correspond to a directory, as Ivan Shatsky mentioned in a comment.

I would rewrite these location blocks as:

# This doesn't even need a location
rewrite /api(/.*)? /api/index.php?$1 last;

location /api/index.php {
    alias /var/www/api/public;

    try_files $uri =404;

    include snippets/fastcgi-php.conf;
    fastcgi_param SCRIPT_FILENAME $request_filename;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

This should also allow you to use /api as a path without the trailing slash, though as Ivan Shatsky also pointed out, this is not a good practice to get into.


View the full question and any other answers on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.