关于NGINX配置来解决CORS跨域资源共享的分析

跨域主要涉及4个响应头:

  • Access-Control-Allow-Origin 用于设置允许跨域请求源地址 (预检请求和正式请求在跨域时候都会验证)
  • Access-Control-Allow-Headers 跨域允许携带的特殊头信息字段 (只在预检请求验证)
  • Access-Control-Allow-Methods 跨域允许的请求方法或者说HTTP动词 (只在预检请求验证)
  • Access-Control-Allow-Credentials 是否允许跨域使用cookies,如果要跨域使用cookies,可以添加上此请求响应头,值设为true(设置或者不设置,都不会影响请求发送,只会影响在跨域时候是否要携带cookies,但是如果设置,预检请求和正式请求都需要设置)。不过不建议跨域使用(项目中用到过,不过不稳定,有些浏览器带不过去),除非必要,因为有很多方案可以代替。

CORS 预检请求不能包含凭据。预检请求的响应必须指定Access-Control-Allow-Credentials: true 来表明可以携带凭据进行实际的请求

在响应附带身份凭证的请求时:

  • 服务器不能将 Access-Control-Allow-Origin 的值设为通配符“*”,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com。
  • 服务器不能将 Access-Control-Allow-Headers 的值设为通配符“*”,而应将其设置为标头名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
  • 服务器不能将 Access-Control-Allow-Methods 的值设为通配符“*”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET

 

问题1:Access to XMLHttpRequest at 'http://xxxxx/iptv/public/index.php/api/api/uploadFile' from origin 'http://xxxxx' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

解决:CORS 机制跨域会首先进行 preflight(一个 OPTIONS 请求即预检请求), 该请求成功后才会发送真正的请求,注意对预检请求进行处理,这里预检请求响应头缺少了Access-Control-Allow-Origin参数,进行配置下就可以,如下:

 

add_header Access-Control-Allow-Origin '*';

 

问题2:Access to XMLHttpRequest at 'http://192.168.100.192/iptv/public/index.php/api/api/uploadFile' from origin 'http://192.168.100.193' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

解决:跨域OPTIONS 预请求没有收到ok状态码,这时候需要给浏览器返回一个状态码,一般是204,意思是请求成功,但是没有数据不进行页面的跳转,注意if的格式抒写不要错误if跟()中间要有空格,如下:

 

if ($request_method = 'OPTION') {

  return 204;

}

 

问题3:Access to XMLHttpRequest at 'http://192.168.100.192/iptv/public/index.php/api/api/updatePlatform' from origin 'http://192.168.100.193' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

解决:这里请求携带了身份凭证(通常是Cookie),Access-Control-Allow-Origin就不能再设置成通配符'*'了,要指定具体的域名,可以用$http_origin取得当前来源域,同时设置Access-Control-Allow-Credentials的值为true,如下:

 

add_header Access-Control-Allow-Origin $http_origin;

add_header Access-Control-Allow-Credentials 'true';

 

问题4:Access to XMLHttpRequest at 'http://192.168.100.192/iptv/public/index.php/api/api/updatePlatform' from origin 'http://192.168.100.193' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

 解决:带有凭据的请求要设置Access-Control-Allow-Credentials的值为true,如下:

 

add_header Access-Control-Allow-Credentials 'true';

 

问题5:Access to XMLHttpRequest at 'http://192.168.100.192/iptv/public/index.php/api/api/updatePlatform' from origin 'http://192.168.100.193' has been blocked by CORS policy: Request header field token is not allowed by Access-Control-Allow-Headers in preflight response.

解决:其中token也可能时其他的名词,这里我前端接口用的是token,自定义添加的头信息是不允许的,需要添加到请求响应头Access-Control-Allow-Headers中,以便浏览器知道此头信息的携带是服务器承认合法的,如下:

 

add_header Access-Control-Allow-Headers 'token';

 

问题6:Access to XMLHttpRequest at 'http://localhost:22222/api/Login/TestGet' from origin 'http://localhost:8080' has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.

 解决:请求响应头Access-Control-Allow-Methods跨域默认只支持POST和GET,当出现其他请求方式时就会跨域异常,这里也是本着缺什么就加什么的方式,同时Access-Control-Allow-Headers请求响应头又会自动校验content-type这个请求头,所以也要设置,如下:

 

add_header Access-Control-Allow-Methods 'PUT';

add_header Access-Control-Allow-Headers 'content-type';

 

问题7:Access to XMLHttpRequest at 'http://localhost:22222/api/Login/TestGet' from origin 'http://localhost:8080' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*', http://localhost:8080', but only one is allowed

解决:出现这种问题情况的问题是NGINX跟服务端都配置了跨域,请求响应头返回了多个,要明确一点那就是要么在NGINX中进行配置,要么在服务端去配置解决跨域!

 

 

 

下面推荐两种配置方法,一种通用写法,一种自定义配置

  通用写法如下:

      add_header Access-Control-Allow-Origin $http_origin always;

      add_header Access-Control-Allow-Headers '*';

      add_header Access-Control-Allow-Methods '*';

      add_header Access-Control-Allow-Credentials 'true';

      add_header Cache-Control private;

      if ($request_method = 'OPTIONS') {

        return 204;

     }

  自定义写法如下:

      add_header Access-Control-Allow-Origin $http_origin;

      add_header Access-Control-Allow-Credentials 'true';

      add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';

      add_header Acess-Control-Allow-Headers 'User-Agent,Origin,Content-Type,Accept,Authorization,X-Token';

               add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';

      add_header Cache-Control private;

                if ($request_method = 'OPTIONS') {

                     return 204;

                }

 

 

posted @ 2023-02-06 13:05  thomas张  阅读(4417)  评论(0编辑  收藏  举报