nginx反向代理解决跨域

面试遇坑

面试官: 你知道跨域有什么解决办法吗?
神仙朱: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

log

配置服务器请求匹配路径

在 (location / )后面加上另一个自定义路径配置
这里我的路径是 /ho/ 也就是说如果我发送的请求中带有 ho ,那么就会匹配成功。
比如 发送请求是 “http://localhost:8089/ho/haha/api/get_goods" , 里面包含 ho,所以匹配成功

1
2
3
4
5
6
7
8
9
10
11
12
13

# 这是原有的,只是为了找个对比位置
location / {
root html;
index index.html index.htm;
}

# 这是新增的
location /ho/ {
rewrite ^.+ho/(.*)$ /$1 break;
proxy_pass https://jingyan.baidu.com/ ;
}

下面照着上面的配置来详细说明一下

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 中

log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<title>nginx 反向代理解决跨域</title>
</head>
<body>
<div></div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
$.get("http://localhost:8089/ho/api/v4/answers/244453931/concerned_upvoters?limit=5&offset=0", function(result) {
console.log(result,3233333333333)
});
})
</script>
</body>
</html>

然后打开这个页面,打开链接 http://localhost:8089/nginx.html

最后我们可以在控制台看到请求返回的信息

log
我还能说什么?不就是成功了喽

结尾

在做项目的时候,调用后端项目的时候总是会涉及到跨域。
而JSONP需要后端配合根本就是很少用,要不然也只能去求后端爸爸设置一下响应头部
现在,我们不用求别人了!!靠自己,就能解决跨域问题!!!

坚持原创技术分享,您的支持将鼓励我继续创作!