修复“ Access-Control-Allow-Origin”标头包含NGINX中的多个值错误

时间:2019-05-09 10:13:19

标签: wordpress nginx cors

我正在建立一个Wordpress网站(例如http://api.example.com),以便从另一个静态HTML / JS网站(例如https://test.example.com)使用其API。

两个网站都托管在Nginx服务器上,并且每个网站都配置有conf文件,并且可以单独正常运行。 nginx -t没有错误,并且我可以按预期完全访问两个网站。

不幸的是,我遇到了CORS的问题。 尝试从api.example.com中读取媒体(图像,视频)内容时,test.example.com在浏览器控制台中产生以下错误:

Access to XMLHttpRequest at 
'https://api.example.com/wp-json/custom-post/v1/some-data/' 
from origin 'https://test.example.com' has been blocked by CORS policy: 

The 'Access-Control-Allow-Origin' header contains multiple values
'https://test.example.com, https://test.example.com', 
but only one is allowed.

此外,在Chrome上,此错误之后是CORB错误(Cross-Origin Read Blocking (CORB) blocked cross-origin response https://api.example.com/wp-json with MIME type application/json.)。

在浏览器中检查请求标头时,我注意到这些属性的冗余值:

Access-Control-Allow-Credentials: true, true
Access-Control-Allow-Origin: https://test.example.com, https://test.example.com

感觉到某处可能有多余的Access-Control-Allow-Origin,我一直在nginx.conf文件中寻找它,而在conf中的所有sites-enabled文件中寻找它都没有用。我还查看了Wordpress应用程序的源代码(包括附带的插件)中是否注入了此标头。没有找到。

最后,我尝试删除api.example.com.conf中添加Access-Control-Allow-Origin标头的一行-它在浏览器控制台中对媒体内容产生了纯粹而简单的No 'Access-Control-Allow-Origin' header is present on the requested resource错误。 有趣的是,它不再产生JSON的CORB错误,并且test.example.com能够从JSON文件读取文本内容。

这是api.example.com.conf文件的内容:

server {
    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    root /var/www/example.com/backend;
    server_name api.example.com;
    access_log /var/log/nginx/unicorn_access.log;
    error_log /var/log/nginx/unicorn_error.log;

    charset                     utf-8;
    gzip                        off;

    # Set CORS policy
    set $cors_origin            "";
    set $cors_cred              "";
    set $cors_header            "";
    set $cors_method            "";

    if ($http_origin ~ '^https?:\/\/(localhost|test.example\.com)$') {
        set $cors_origin        $http_origin;
        set $cors_cred          true;
        set $cors_header        $http_access_control_request_headers;
        set $cors_method        $http_access_control_request_method;
    }

    add_header Access-Control-Allow-Origin      $cors_origin;
    add_header Access-Control-Allow-Credentials $cors_cred;
    add_header Access-Control-Allow-Headers     $cors_header;
    add_header Access-Control-Allow-Methods     $cors_method;

    location / {
        index                   index.php index.html;
        try_files               $uri $uri/ /index.php?$args;
    }

    client_max_body_size        50m;

    # Add trailing slash to */wp-admin requests.
    rewrite /wp-admin$ $scheme://$host$uri/ permanent;

    # Prevents hidden files (beginning with a period) from being served
    location ~ /\. {
        access_log              off;
        log_not_found           off;
        deny                    all;
    }

    # Send 'expires' headers and turn off 404 logging
    location ~* ^.+.(xml|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
        access_log              off;
        log_not_found           off;
        expires                 max;
    }

    # Pass all .php files onto a php-fpm or php-cgi server
    location ~ \.php$ {
        try_files               $uri =404;
        include                 /etc/nginx/fastcgi_params;
        fastcgi_read_timeout    3600s;
        fastcgi_buffer_size     128k;
        fastcgi_buffers         4 128k;
        fastcgi_param           SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass            unix:/run/php/php7.2-fpm.sock;
        fastcgi_index           index.php;
    }

    # Robots
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # Restrictions
    location ~* /(?:uploads|files)/.*\.php$ {
        deny all;
    }
}

我希望test.example.com会使用api.example.com中的任何内容,但是我不能完全这样做。

感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

这是由于rest_send_cors_headers过滤器将REST API钩子插入了rest_pre_serve_request中。它使用API requests发送了CORS标头。

可以通过以下操作将其关闭:

add_action('rest_api_init', function() {
    remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
}, 15);