nginx解决跨域问题

 1.1 什么是跨域问题?

在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。

一般根据错误来定位是否是跨域问题,报错如下:

 

或者:

 

1.2 常见的跨域场景

 

URL

说明

是否允许通信

http://www.domain.com/a.js
http://www.domain.com/b.js
http://www.domain.com/lab/c.js

同一域名,不同文件或路径

允许

http://www.domain.com:8000/a.js
http://www.domain.com/b.js

同一域名,不同端口

不允许

http://www.domain.com/a.js
https://www.domain.com/b.js

同一域名,不同协议

不允许

http://www.domain.com/a.js
http://192.168.4.12/b.js

域名和域名对应相同ip

不允许

http://www.domain.com/a.js
http://x.domain.com/b.js
http://domain.com/c.js

主域相同,子域不同

不允许

http://www.domain1.com/a.js
http://www.domain2.com/b.js

不同域名

不允许

 

 

1.3 如何解决跨域问题?

目前我了解的解决跨域的几种方式:手写过滤器,手写拦截器,jsonnp,注解方式,配置nginx反向代理,共五种解决方式。

我们通常采用修改nginx配置文件来解决跨域问题

1.3.1 nginx代理跨域

nginx代理跨域,实质和CORS跨域原理一样,通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段。

1)  nginx配置解决iconfont跨域

浏览器跨域访问js、css、img等常规静态资源被同源策略许可,但iconfont字体文件(eot|otf|ttf|woff|svg)例外,此时可在nginx的静态资源服务器中加入以下配置。

 

2)  nginx反向代理接口跨域

跨域问题:同源策略仅是针对浏览器的安全策略。服务器端调用HTTP接口只是使用HTTP协议,不需要同源策略,也就不存在跨域问题。

实现思路:通过Nginx配置一个代理服务器域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域访问。

nginx具体配置:

server {

      listen   8888;

      server_name test.demo.com;

      location / {

      proxy_pass http://120.147.88.27:8888;

      add_header Access-Control-Allow-Origin *;

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

      add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,Authorization,Accept,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';

      #add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,Accept';

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

        }

}


详细解释:

add_header Access-Control-Allow-Methods *;

add_header Access-Control-Allow-Origin $http_origin;

 

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 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';

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

if ($request_method = 'OPTIONS') {

      add_header 'Access-Control-Max-Age' 1728000;

      add_header 'Content-Type' 'text/plain; charset=utf-8';

      add_header 'Content-Length' 0;

      return 204;

    }

 

1、Access-Control-Allow-Origin,这里使用变量 $http_origin取得当前来源域,大家说用“*”代表允许所有,我实际使用并不成功,原因未知;

2、Access-Control-Allow-Credentials,为 true 的时候指请求时可带上Cookie,自己按情况配置吧;

3、Access-Control-Allow-Methods,OPTIONS一定要有的,另外一般也就GET和POST,如果你有其它的也可加进去;

4、Access-Control-Allow-Headers,这个要注意,里面一定要包含自定义的http头字段(就是说前端请求接口时,如果在http头里加了自定义的字段,这里配置一定要写上相应的字段),从上面可看到我写的比较长,我在网上搜索一些常用的写进去了,里面有“web-token”和“app-token”,这个是我项目里前端请求时设置的,所以我在这里要写上;

5、Access-Control-Expose-Headers,可不设置,看网上大致意思是默认只能获返回头的6个基本字段,要获取其它额外的,先在这设置才能获取它;

6、语句“ if ($request_method = 'OPTIONS') { ”,因为浏览器判断是否允许跨域时会先往后端发一个 options 请求,然后根据返回的结果判断是否允许跨域请求,所以这里单独判断这个请求,然后直接返回;

#   指定允许跨域的方法,*代表所有

add_header Access-Control-Allow-Methods *;

#   预检命令的缓存,如果不缓存每次会发送两次请求

add_header Access-Control-Max-Age 3600;

#   带cookie请求需要加上这个字段,并设置为true

add_header Access-Control-Allow-Credentials true;

#   表示允许这个域跨域调用(客户端发送请求的域名和端口)

#   $http_origin动态获取请求客户端请求的域   不用*的原因是带cookie的请求不支持*号

add_header Access-Control-Allow-Origin $http_origin;

#   表示请求头的字段 动态获取

add_header Access-Control-Allow-Headers  $http_access_control_request_headers;

1.4 问题1:配置跨域不生效

1)使用nginx -V进行查看是否存在header模块,如没有则进行重新编译安装nginx

    --prefix=/app/nginx --with-http_ssl_module --with-stream --add-module=nginx-upload-module-2.2 --add-module=headers-more-nginx-module-master

2)下载这两个模块编译即可

    headers-more-nginx-module-master.zip

    nginx-upload-module-2.2.zip

 

1.5 问题2: nginx会去掉带有下划线的Header键值

原因:nginx对header name的字符做了限制,默认 underscores_in_headers 为off,表示如果    header name中包含下划线,则忽略掉,部署后就获取不到。

解决:在header里不要用 “_” 下划线,可以用驼峰命名或者其他的符号(如减号-)代替。nginx默认忽略掉下划线可能有些原因。

在nginx里的 nginx.conf文件中配置http的部分添加 : underscores_in_headers on;(默认值是off)

原文地址:https://www.cnblogs.com/Leonardo-li/p/13354038.html