利用Nginx代理如何解决前端跨域问题详析
前言
Nginx(发音同“engineX”)是异步框架的网页服务器,也可以用作反向代理、负载平衡器和HTTP缓存。
本文将讲述如何使用Nginx在Web前后端分离开发中实现路由的转发。
Web开发通常使用的是前后端分离的开发模式,即前端和后端分别进行开发,前端通过Ajax请求后端的接口,将获取数据将数据渲染到页面上。前端开发会使用脚手架搭建前端开发环境,其底层通常会启动一个本地服务器,通常使用的是nodejs的Express框架。而后端则是提供接口,一般是放在线上的一个开发用的域名下。
这在开发过程中会导致跨域问题,即在一个域名下的网页,是无法通过Ajax请求另一个(不同源)域名下的接口API的。这是浏览器的同源策略,是浏览器的一个非常重要的安全策略。
解决这个问题的其中一个方案是使用代理。具体来说,就是在本地启动一个服务器(如localhost:4000),发送给该服务器的请求会根据请求路由(比如判断url是否有前缀/api)进行转发,分别转发到前端开发的服务器(如localhost:3000),以及后端服务器(比如dev.yoursite.com)。这样通过一个代理服务器,因为请求的api都是同一个域名下的,自然就不会造成跨域问题,从而导致请求失败。
下面我们就来讲解如何使用Nginx来实现反向代理。
简单认识Nginx配置文件
安装好Nginx后,我们需要确定下Nginx的默认配置文件的位置。执行命令nginx-t,该命令会检测nginx的默认配置文件语法是否正确,并进行测试,最后输出结果。我们可以从输出中得到默认配置文件所在的位置。
nginx:theconfigurationfile/etc/nginx/nginx.confsyntaxisok nginx:configurationfile/etc/nginx/nginx.conftestissuccessful
还有另外一种方法可以得到默认配置文件的位置,那就是执行nginx-h。该命令会输出nginx的简易帮助文档,其中的-cfilename的配置项说明也指出了默认配置项的路径。
-cfilename:setconfigurationfile(default:/etc/nginx/nginx.conf)
通过这个文档,我们也可以知道,使用-c配置项可以自定义配置文件。如果不指定文件,使用默认配置文件。
下面我们来修改一下Nginx到这个默认配置文件nginx.config来首先代理功能。
nginx.config文件的http后面的代码块中,应该会有类似下面这行的代码:
include/etc/nginx/conf.d/*.conf;
这行代码的作用是将/etc/nginx/conf.d目录下的后缀为.conf的文件内容嵌入到引入位置中,作为配置的一部分执行。
如果你是在macOS安装的Nginx,可能会有点不同。我使用brew安装的Nginx为为includeservers/*;,对应嵌入的是servers目录下的所有文件。
为什么会用到这种嵌入的语法呢?因为这样我们就可以将不同项目需要用到的配置放到不同的配置文件里,好处就是可以快速地找到对应项目要修改的配置文件,不用担心不小心修改了其他项目的配置。另外如果直接在nginx.conf上修改,使其变得臃肿。这符合设计模式的单一职责原则。
此外,你可以会奇怪conf.d目录的命名为什么要加上.d?如果你使用Linux过一段时间,你会发现某些目录或文件的末尾会加上一个d,比如httpd、crond、vsftpd等。其实这是为了说明这些文件都属于是daemon(服务)。这里的服务指的是系统的服务,主要分为系统本身需要的服务,以及负责网络的服务。我们的conf.d就是属于后者。
编写Nginx配置文件
我们在conf.d目录下创建名为demo.conf的文件,写入以下内容,然后启动Nginx。
server{ listen5000; server_namelocalhost; location/{ proxy_passhttp://localhost:3000; } location/api/{ proxy_passhttp://localhost:4000; } }
该配置启用了localhost:5000的服务器,将localhost:5000下开头为/api/url请求代理到了localhost:4000(后端接口服务器)。其他请求则是代理到localhost:3000(前端)。下面我们具体解析一下配置文件里面内容的作用。
listen设置了服务器的端口号,server_name则设置了主机名。
location
location表示进行路由的匹配,如果匹配则执行对应代码块里的操作。location可以使用前缀匹配以及正则匹配(需要以~*或~开头)。我们这里的配置使用的是前缀匹配。
这里有个点需要注意一下,Nginx的路由匹配和一般的按顺序匹配第一个的路由匹配方案(比如后端的gin、前端的vue-router的路由匹配方案)不同,nginx匹配路由的方式为:
- 首先进行前缀匹配,遍历所有的前缀匹配,从中选择前缀匹配最长的;
- 然后会进行正则匹配,在所有正则匹配中,从前往后选择第一个符合的;
- 如果能找到匹配的正则匹配,使用其对应的配置;如果没有,则使用之前找到的那个最长的前缀匹配对应的配置。
所以,当请求为localhost:5000/api/xx时,/和/api/都能够前缀匹配。根据规则,虽然位置更靠前的/也符合前缀匹配,但/api更长,所以最终匹配的是/api。
proxy_pass
确定好匹配的location后,我们再看看proxy_pass又做了什么操作。proxy_pass用于将请求路由映射到指定的协议和地址。本质是将发送给Nginx的请求处理并发送到另一个服务器,然后将返回的数据作为Nginx的返回数据返回。
proxy_pass后如果使用的是URI(端口后面至少有一个/),那么Nginx就会替换掉location匹配的那部分字符。
listen5000; server_namelocalhost; location/name/{ proxy_passhttp://127.0.0.1/remote/; } #localhost:5000/name/fstar #会被映射请求为 #127.0.0.1/remote/fstar
可以看到,/name/的部分在映射时被移除(或者说是替换)了。
proxy_pass后如果使用的是不是URI(端口后没有任何东西),Nginx会将源请求完全映射到代理服务上:
listen5000; server_namelocalhost; location/some/path/{ proxy_passhttp://127.0.0.1; } #localhost:5000/some/path/x/y #会被映射请求为 #127.0.0.1/some/path/x/y
这里的/some/path并没有被移除。
我们的demo.conf文件的proxy_pass使用的不是URI,所以是将路由完全映射到另一个服务。
思考题
请问,下面有两段配置(区别是proxy_pass结尾是否有/)?如果请求/kite/api/xx,分别会映射为什么?
location/kite/api/{ proxy_passhttp://localhost:5000; }
location/kite/api/{ proxy_passhttp://localhost:5000/; }
前面我们讲proxy_pass的时候说过,proxy_pass后面如果不是URI,会正常转发;如果是URI,就移除location匹配的前缀再进行转发,体现的是替换路由的效果。上面这两个配置的区别就在于末尾的这个/,有/是URI,没有的不是URI,从而导致完全不一样的结果,依次分别为:
http://localhost:5000/kite/api/xx http://localhost:5000/xx
所以,在写Nginx配置的时候,一定要注意端口后面的/是否有必要保留。因为它的有无会导致两种截然不同的效果。
参考文章
- Nginx官方文档
- stackoverflow-HowdoIrewriteURLsinaproxyresponseinNGINX
总结
到此这篇关于利用Nginx代理如何解决前端跨域问题的文章就介绍到这了,更多相关Nginx代理解决前端跨域内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。