定制化开发Nginx跨域解决方案

前置条件:
定制化开发前端网站地址:http://localhost:4443
定制化开发服务端网址:http://localhost:9081

当网站8080定制化开发访问服务端接口的时候定制化开发会产生跨域的问题

定制化开发跨域主要设计到4个响应头:

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

跨域请求时会先发送预检请求,浏览器首先会询问服务器,当前网页所在的域名是否在服务器的许可列表中,以及可以使用的请求头和请求方法。若得到肯定的答复,才会发送正式请求Xhr请求,否则报错

报错情况1

Access to XMLHttpRequest at ‘http://localhost:9081/api/’ from origin ‘http://localhost:4443’ 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.

通过错误信息可以很清晰的定位到错误priflight说明是个预请求,CORS 机制跨域会首先进行 preflight(一个 OPTIONS 请求), 该请求成功后才会发送真正的请求。这一设计旨在确保服务器对 CORS 标准知情,以保护不支持 CORS 的旧服务器

解决方案:

server {    listen       8080;    server_name  localhost;    location  / {        add_header Access-Control-Allow-Origin 'http://localhost:4443';        proxy_pass  http://localhost:9081;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

报错情况2

Access to XMLHttpRequest at ‘http://localhost:9081/api/’ from origin ‘http://localhost:4443’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.

通过报错信息提示可以得知,是跨域浏览器默认行为的预请求(option请求)没有收到ok状态码,此时再修改配置文件,当请求为option请求时候,给浏览器返回一个状态码(一般是204)

如果想要每次响应信息都携带头字段信息,需要在最后添加always(经我测试,只有Access-Control-Allow-Origin这个头信息需要加always,其他的不加always也会携带回来)

server {    listen       8080;    server_name  localhost;    location  / {        add_header Access-Control-Allow-Origin 'http://localhost:4443' always;        if ($request_method = 'OPTIONS') {            return 204;        }        proxy_pass  http://localhost:9081;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

报错情况3

Access to XMLHttpRequest at ‘http://localhost:9081/api/’ from origin ‘http://localhost:4443’ has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.
意思就是预请求响应头Access-Control-Allow-Headers中缺少头信息(各种情况会不一样,在发生跨域后,在自定义添加的头信息是不允许的,需要添加到请求响应头Access-Control-Allow-Headers中,以便浏览器知道此头信息的携带是服务器承认合法的)

server {    listen       8080;    server_name  localhost;    location  / {        add_header Access-Control-Allow-Origin 'http://localhost:4443' always;        if ($request_method = 'OPTIONS') {            add_header Access-Control-Allow-Headers '*'; #为什么写在if里面而不是接着Access-Control-Allow-Origin往下写?因为这里只有预检请求才会检查            return 204;        }        proxy_pass  http://localhost:9081;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

报错情况4
如果`if ($request_method = ‘OPTIONS’)``中配置了add_header,那么预检请求外部配置均会失效
官方文档

There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.

意思就是当前层级无 add_header 指令时,则继承上一层级的add_header。相反的若当前层级有了add_header,就应该无法继承上一层的add_header。

server {    listen       8080;    server_name  localhost;    location  / {        add_header Access-Control-Allow-Origin 'http://localhost:4443' always;        if ($request_method = 'OPTIONS') {            add_header Access-Control-Allow-Origin 'http://localhost:4443';            add_header Access-Control-Allow-Headers '*'; #为什么写在if里面而不是接着Access-Control-Allow-Origin往下写?因为这里只有预检请求才会检查            return 204;        }        proxy_pass  http://localhost:9081;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

但是由于此写法携带上两个 Access-Control-Allow-Origin ,这种情况也是不允许的
因此修正过的配置如下(其中*可以根据自己的需求替换

server {    listen       8080;    server_name  localhost;    location  / {        if ($request_method = 'OPTIONS') {            add_header Access-Control-Allow-Origin 'http://localhost:4443';            add_header Access-Control-Allow-Headers '*'; #为什么写在if里面?因为这里只有预检请求才会检查            add_header Access-Control-Allow-Methods '*';            add_header Access-Control-Allow-Credentials 'true';            return 204;        }        if ($request_method != 'OPTIONS') {            add_header Access-Control-Allow-Origin 'http://localhost:4443' always;            add_header Access-Control-Allow-Credentials 'true';        }        proxy_pass  http://localhost:9081;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

或者

server {    listen       8080;    server_name  localhost;    location  / {        add_header Access-Control-Allow-Origin 'http://localhost:4443' always;        add_header Access-Control-Allow-Headers '*';        add_header Access-Control-Allow-Methods '*';        add_header Access-Control-Allow-Credentials 'true';        if ($request_method = 'OPTIONS') {            return 204;        }        proxy_pass  http://localhost:9081;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发