面试遇坑
面试官: 你知道跨域有什么解决办法吗?
神仙朱:JSONP 或者 后端修改相应头部 Accept-Control-Allow-Origin ??
面试官:看你还用过 nginx 啊,不知道 nginx 可以反向代理解决跨域吗 ?
我心想还有这种操作 ??于是我很自信地回答他我不知道
素来我是遇到问题一定要解决的,没有什么东西可以一直困扰我。
于是上网查了大量资料(其实就一两篇文章),然后就尝试配置了一下 nginx ,最后真的解决了!!
现在我就来做一份自己的总结!
先来把几个关键知识点理一下
跨域
浏览器的同源策略 导致跨域! 注意是浏览器,只有在浏览器才存在有跨域。
也就是说 服务器上不存在 跨域 的说法。
所以才存在今天使用 服务器代理解决跨域的方法。
跨域的请求过程
跨域请求一般浏览器是可以发送跨域请求的,只是响应被拦截了。
而 chrome 下会先发一个 options 请求去询问浏览器是否可以跨域,并且对这个请求结果进行缓存。
如果 options 请求得到 跨域不允许,那么下一次跨域的时候不会再发送新的 options 请求 ,而是直接报跨域错误。
代理
正向代理
正向代理是隐藏客户端,服务器不知道真正的请求人。
比如你想访问某个网站,但是没有直接去访问,而是通过一个 代理服务器去访问 这个网站,利用代理服务器帮你发送请求,再把请求返回的信息转发给你。
上面的过程中,那个网站的服务器根本不知道到底是谁访问我。那么就达到了隐藏客户端的目的,这就是正向代理。
应用
科学上网:在国外部署代理服务器,通过这个代理服务器 实现代发请求,就可以科学上网
反向代理
反向代理 是隐藏服务器。客户端不知道真正的服务人。因为服务器会自动分配服务你的服务器,而你不知道真正给你提供服务的是谁。
比如我们访问淘宝,淘宝的服务器有很多。当我们访问淘宝的时候,淘宝服务器会将我们的请求转发给其他服务器。这时,淘宝服务器实现的功能就是 方向代理。
nginx 反向代理解决跨域
配置 window nginx 来测试一下
安装 nginx
- 访问官网下载: http://nginx.org/en/download.html
- 选择 window 版本,比如 nginx/Windows-1.12.2
- 下载成功,解压到某个文件夹,比如 D:/nginx
- ok
启动 nginx
- Ctrl+R 打开 CMD
- 进入到刚刚解压的文件夹
- 运行命令 ./nginx.exe
- 正常情况下,启动成功没有任何提示
配置 nginx
进入到解压的文件夹,比如D:/nginx
进入 conf 文件夹,看到nginx.conf 就是配置文件,打开它,
修改端口
原来nginx 的端口是80,不过window 下 80端口可能被 System 占用了,所以我们换一个端口 ,比如是 8089
配置服务器请求匹配路径
在 (location / )后面加上另一个自定义路径配置
这里我的路径是 /ho/ 也就是说如果我发送的请求中带有 ho ,那么就会匹配成功。
比如 发送请求是 “http://localhost:8089/ho/haha/api/get_goods" , 里面包含 ho,所以匹配成功
1 |
|
下面照着上面的配置来详细说明一下
rewrite
rewrite 的组要功能是实现RUL地址的重定向,就是进行 URL重写。
我们的目的是去掉域名和匹配的路径,保留url正确的api路径
这里使用了一个正则去匹配URL,/^.+ho/(.*)$/,正则不解释了。
举例
假设我们现在要在本地网页localhost通过 ajax 访问一个接口
http://jingyan.baidu.com/asyncreq/log?method=getLog&likeNum=39010735291423126980&type1423=6557184
一般情况下,这是会跨域的
而我们的目的就是想可以通过本地网页成功访问服务器接口!!
所以先在本地构建一个接口,通过这个接口去转发到真正的接口上去!!!!
http://localhost:8089/ho/asyncreq/log?method=getLog&likeNum=39010735291423126980&type1423=6557184
回到nginx配置上来,看到 rewrite 设置为 ^.+ho/(.*)$ /$1 break
不急,我们先尝试使用上面的正则去匹配URL测试最后会得到什么1
2/^.+ho\/(.*)$/.exec("http://localhost:8089/ho/asyncreq/log?method=getLog&likeNum=39010735291423126980&type1423=6557184")
// 测试得到了一个数组 ["http://localhost:8089/ho/asyncreq/log?method=getLog&likeNum=39010735291423126980&type1423=6557184", "api/v4/answers/244453931/concerned_upvoters?limit=5&offset=0"]
看到 rewrite 还有一个 $1,就是取数组的第二个的意思
那么得到可以得到
“/asyncreq/log?method=getLog&likeNum=39010735291423126980&type1423=6557184”
就是这个没错了,我们就要这个
proxy_pass
proxy_pass 的作用是设置被代理的服务器的协议和地址
- 协议可以是 http 或者 https
- 地址可以是 域名 或者 IP+端口
既然拿到了 正确的api路径,那么我们现在要做的就是确定要真正发送请求的服务器的域名
比如是 https://jingyan.baidu.com
所以设置 proxy_pass 为 https://jingyan.baidu.com
那么最后我们发出去的请求就是
http://jingyan.baidu.com/asyncreq/log?method=getLog&likeNum=39010735291423126980&type1423=6557184
重启nginx
我们已经修改了配置文件了,现在要做的就是重启nginx
运行命令 nginx -s reload
到这一步,nginx 相关的我们都做完啦,下面就写一个页面测试一下接口反向代理是否成功
写测试页面
新建一个 nginx.html 文件放在 nginx解压目录下的 html 中
1 |
|
然后打开这个页面,打开链接 http://localhost:8089/nginx.html
最后我们可以在控制台看到请求返回的信息
我还能说什么?不就是成功了喽
结尾
在做项目的时候,调用后端项目的时候总是会涉及到跨域。
而JSONP需要后端配合根本就是很少用,要不然也只能去求后端爸爸设置一下响应头部
现在,我们不用求别人了!!靠自己,就能解决跨域问题!!!