Ajax跨域问题
背景
我自己现在正在做的项目采用的是前后端分离的架构,前端是react,生成静态文件部署在CDN中.后端是nginx+tomcat的标准java web项目.在java web项目中只需要放一个index.html就可以了.由于java端的接口已经预先发布上线,前端开发过程中直接使用线上API进行调试,所以就碰到了跨域问题.
插播
为了测试跨域问题,本机最好先安装一个nginx.mac上安装nginx当然首推homebrew.不过由于速度太慢,建议换成国内的源.比如中科大.可以用brew config
查看是否设置正确.然后直接用
1 | brew install nginx |
homebrew装出来的都在/usr/local/
目录中,nginx配置文件在:/usr/local/etc/nginx/nginx.conf
,静态文件在/usr/local/var/www
,安装完nginx后我们继续
模拟
正式开始模拟前最好先熟悉一下基本概念,阮一峰有篇blog讲的非常详细也很易懂.不太明白的同学先看看这里.下面我们开始模拟,首先需要有两个不同domain的应用.假设我们从A应用(localhost)用ajax跨域去请求B应用(siteb.com)的资源.为了看起来比较真实,我把siteb.com映射到了127.0.0.1.同时起了一个普通的java web当做A应用,index.html的代码如下:
1 |
|
这时候浏览器会报一个错误:
XMLHttpRequest cannot load http://siteb.com:9000/index.html. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8080‘ is therefore not allowed access.
原因就是nginx上的B应用(siteb.com)在http的response头中没有设置Access-Control-Allow-Origin.
加上配置再试试
1 | location / { |
果然就好了.这样就搞定了?这只是搞定了最简单的情况,接下来我们再看一下稍微复杂一点的情况.
麻烦点的
上面举的例子是不需要发送cookie的,不过很多场景都是需要的.所以再看看发送cookie的场景是怎么支持的.默认是不发送的.需要修改一下jquery的ajax配置
1 |
|
同时需要在siteb的nginx设置中加上
1 | location / { |
我预先已经在siteb.com的请求中设置了一个cookietest=1024
.刷新一下可以看到这个时候的ajax请求已经把siteb的cookie带上了,但是又出现了另外一个错误
XMLHttpRequest cannot load http://siteb.com:9000/index.html. A wildcard ‘*’ cannot be used in the ‘Access-Control-Allow-Origin’ header when the credentials flag is true. Origin ‘http://localhost:8080‘ is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
意思就是当withCredentials=true
时,Access-Control-Allow-Origin
与请求的origin必须 严 格一致.再次修改nginx的配置:
1 | location / { |
再次刷新已经没有报错了.done!
再啰嗦一下
线上环境是没有这个问题的,因为都是同一个域发出的请求,那线下环境要跨域调试怎么办呢?一般来说有两种方式:
- 将线上环境的nginx
Access-Control-Allow-Origin
开放成localhost+固定端口号专门用于测试 - 可以在本地起一个nginx,把静态文件放进去,同时设置代理掉线上的API,模拟出同域的效果.