起于安全

跨域请求(CORS)的响应在特定的情况下被浏览器拦截,这是因为请求了一个与当前域或端口不同的资源。所以通过 JavaScript 操控的 XMLHttpRequestFetch API 都会受到跨域限制。

这样一来,我们在编写 Web 程序时只能从加载同一域请求 HTTP 资源,除非 HTTP 响应头中指定了:

Access-Control-Allow-Origin: *;

它允许 HTTP 服务器声明哪些站点有权限访问该资源。

在浏览器发出跨域请求前,有可能先用 OPTIONS 方法发起一个预检请求来询问服务端是否支持跨域。

反向代理

源服务器不能修改 HTTP 响应头 ?

在接入后端 API 时,无法即时部署到线上环境测试,在其他地方部署都会触发 CORS 限制。

将前端代码转移到测试服务器上,使用 Nginx proxy_pass 来代理需要测试的 API :

server {
    listen       80;
    server_name  test.misaka.im;
    root         /var/www/html/test/public;
    index        index.html index.htm index.php;

    location ^~/jiushou/ {
        rewrite     ^/jiushou/app/(.*)$ /$1 break;
        proxy_pass  https://api.jiushouguoji.hk/app/;
    }
}

访问 test.misaka.im/jiushou/ 的请求就会被转发到 https://api.jiushouguoji.hk/app/ 上。

跨域代理

但这样并没彻底解决CORS 限制的问题,每次都要将代码部署到 test.misaka.im 上才能进行测试。

反向代理时加入 HTTP 头,这才是中规中矩的做法:

server {
    listen       80;
    server_name  test.misaka.im;
    root         /var/www/html/test/public;
    index        index.html index.htm index.php;

    location ^~/jiushou/ {
        rewrite     ^/jiushou/app/(.*)$ /$1 break;
        proxy_pass  https://api.jiushouguoji.hk/app/;
    
        if ($request_method = 'OPTIONS') {
            add_header  Access-Control-Allow-Origin *;
            add_header  Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header  Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range;
            add_header  Access-Control-Max-Age 1728000;
            add_header  Content-Type 'text/plain; charset=utf-8';
            add_header  Content-Length 0;
            return      204;
        }
    
        if ($request_method = 'POST') {
            add_header  Access-Control-Allow-Origin *;
            add_header  Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header  Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range;
            add_header  Access-Control-Expose-Headers Content-Length,Content-Range;
        }
    
        if ($request_method = 'GET') {
            add_header  Access-Control-Allow-Origin *;
            add_header  Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            add_header  Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range;
            add_header  Access-Control-Expose-Headers Content-Length,Content-Range;
        }
    }
}

现在所有由 test.misaka.im/jiushou/ 发回的响应都能顺利被浏览器接收了。

参考

CORS on Nginx - https://enable-cors.org

HTTP访问控制(CORS) - MDN

nginx解决跨域

标签: none

添加新评论