nginx解决跨域问题
在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。
一般根据错误来定位是否是跨域问题,报错如下:
或者:
1.2 常见的跨域场景
URL |
说明 |
是否允许通信 |
http://www.domain.com/a.js |
同一域名,不同文件或路径 |
允许 |
同一域名,不同端口 |
不允许 |
|
http://www.domain.com/a.js |
同一域名,不同协议 |
不允许 |
http://www.domain.com/a.js |
域名和域名对应相同ip |
不允许 |
http://www.domain.com/a.js |
主域相同,子域不同 |
不允许 |
http://www.domain1.com/a.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
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)