配置nginx实现反向代理解决跨域问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/HermitSun/article/details/99696277

在开始之前,有两个前置知识点:正向代理和反向代理的区别,为什么会跨域。关于这两个问题,网上有很多资料,参考资料里也有一些我觉得比较好的材料,就只简单提一下。

正向代理需要知道代理服务器和目标服务器,是我们主动通过代理到达目标;而反向代理只需要知道代理就行了,我们把请求交给代理,代理会帮我们交给合适的目标。我们设想这样一个场景,某天中午我们想出去吃一顿(我们是客户端,食物相当于客户端需要的数据),我们决定了吃某家店(目标服务器),结果一看这家店只提供外卖服务(有同源策略限制,客户端无法访问),所以我们就打开外卖软件,请外卖员(代理服务器)给我们送过来(服务器之间的通信不涉及跨域问题),这个过程相当于是正向代理;而对于店家来说,他并不需要知道谁点了单,只要把外卖交给外卖员,外卖员自己会送到合适的客户手里,这个过程相当于是反向代理。

其实所谓的正反向代理,跟设计模式里代理模式是完全一样的。这里有两张图,可以很好地说明这一点(图来自参考资料2):

img

img

接着说跨域的事。之所以会跨域,因为有同源策略。为什么会有同源策略限制呢?为了安全。还用刚才那个例子,为什么这家店只提供外卖服务而不让我们到店里吃呢?因为这家店可能不太干净,为了“安全”,怕我们看到了给差评影响生意。而为了解决这个问题,我们可以伪装成工作人员(通过CORS),这样就能混进店里了。当然了,这个比喻可能不是那么恰当,不过意思是那个意思。


切入正题。比如我要从豆瓣API获取电影数据,我可以用postman发请求拿到数据,因为postman相当于是个服务器,但用浏览器就不行了,因为会跨域。

为了解决跨域问题,对于一个用vue-cli3创建的项目,我们在开发过程中,可以通过修改vue.config.js,增加proxy设置(vue-cli2的配置类似):

module.exports = {
    devServer: {
        port: 8085,
        proxy: {
            '/douban': {
                target: 'https://douban.uieee.com/v2/movie',
                changeOrigin: true,
                pathRewrite: {
                    '^/douban': ''
                }
            }
        }
    }
};

这样配置以后,就可以通过http://localhost:8085/douban来调用豆瓣的API了。举个例子,比如我们用axios,我们可以通过下面的代码获取南京正在上映的前8名的电影:

axios.get('/douban/in_theaters?city=南京&start=0&count=8');

这个请求会被自动代理到https://douban.uieee.com/v2/movie/in_theaters?city=南京&start=0&count=8

但是在生产环境下,这个设置就不起作用了。这个时候,为了解决跨域问题,就需要用服务器反向代理进行转发。对于前端来说,最常用的服务器自然是nginx。一般来说,普通的HTTP请求如果要配置跨域,只需要proxy_pass一下就好了。比如我要直接调用tushare的API来数据:

location /tushare/ {
    proxy_pass http://api.tushare.pro/;
}

这里有一点很重要,location后面一定要有/,不然会被nginx当成对本机的访问,导致出现404。

而豆瓣之类的接口还有点区别,因为用的是HTTPS,还不能直接proxy_pass,必须先配置SSL。首先要确保安装了openssl和openssl-devel,如果是通过apt安装的nginx,这些是已经配置好了的;如果是手动编译安装的话,在configure的时候需要加上--with-http_ssl_module选项来支持SSL。然后就是搞一个证书放到和nginx.conf同级的目录,这个可以自己生成或者去买一个(阿里云之类的有免费的),比如叫cert吧(别的地方也行,只是要确保路径正确),里面放上.pem和.key文件,然后修改nginx.conf:

server {
    listen       443 ssl;
    server_name  wensun.top; 		   # 换成自己的server_name
    ssl_certificate      cert/foo.pem; # 换成自己的pem
    ssl_certificate_key  cert/foo.key; # 换成自己的key
    ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;        
	ssl_prefer_server_ciphers  on;
    
    location / {
        root   html;
        index  index.html index.htm;
    }

	location /v2/ {
	    proxy_pass https://douban.uieee.com/v2/;
	}
}

ssl开头的配置除了ssl_certificate相关的需要换成自己的证书,别的都可以照抄,是一些通用的SSL配置。这样设置完之后,我们就可以代理豆瓣的API了。还是以axios为例:

axios.get('https://wensun.top/v2/movie/in_theaters?city=南京&start=0&count=8');

参考资料

  1. 浏览器同源政策及其规避方法
  2. 正向代理与反向代理区别图解 (nginx)
  3. 搭建nginx反向代理豆瓣api

猜你喜欢

转载自blog.csdn.net/HermitSun/article/details/99696277