前言
本文简单介绍vue代理以及nginx代理的作用以及使用注意事项,解决前端萌新们在使用vue本地开发调用接口以及部署上线时出现的404困惑。文中介绍到的知识点(nginx、http-proxy、vite源码等)感兴趣可以去官网学习。
一、什么是代理?为什么要用代理?
- 什么是代理?
代理就是通过一个特殊的网络服务去访问另一网络服务的一种间接访问方式。像我们不能直接访问国外的网站,只能使用VPN,就是使用了代理。 - 那前端为什么要用代理?
首先明确以下两个概念
(1)前端应用要能访问,那必须是放在服务器上(服务器可以是nginx、nodejs、apache、tomcat等),像我们本地vue开发就是用nodejs启动了一个服务。
(2)由于浏览器的同源策略(协议、ip、端口号都相同为同源),禁止网站向非同源的服务器发送ajax异步请求,也就是跨域。
明白以上两点就知道我们本地开发要调用服务器的接口,就会跨域。解决跨域的手段有很多种,像是cors、jsonp等,但是他们都有缺陷,代理是前端解决跨域的终极手段。
二、代理的使用
vue代理配置
vuecli3的代理设置在vue.config.js->devServer->proxy
vite构建的vue代理设置在 vite.config.js->server->proxy
他们的代理配置是一样的,这里以vuecli3为例
const REQUEST_PRE = "/api"
module.exports = {
// 其他配置省略
// 本地代理配置
devServer: {
// 默认是false,可以将http://localhost:8080 变为 https://localhost:8080
https: true,
// 代理配置
proxy: {
// 简单写法
// 当访问http://localhost:80/normal/getData
// 实际上访问的是 http://localhost:80/normal/getData
"/normal":'http://localhost:80',
"/normal":{
target: 'http://localhost:80',
ws: true, // 允许websocket代理
changeOrigin: true //允许跨域
},
// 变量写法
[REQUEST_PRE]: {
target: 'http://localhost:88',
ws: true,
changeOrigin: true
},
// 重写,当访问http://localhost:80/req/getData
// 实际上访问的是 http://localhost:8888/getData
'/req': {
target: 'http://localhost:8888',
pathRewrite: path => path.replace('/req', '/module'),
ws: true,
changeOrigin: true
},
// 试试看下面两个会被代理到哪去
'/api/normal': 'http://localhost:8888',
'/api/other': 'http://localhost:8888',
},
open: true
}
}
注意(坑点):
1、后面的反斜杠要保持一致,虽然对接口调用没有影响,但是对代理文件的相对路径有影响
如 /req,target就写 http://localhost:8888
如 /req/,target就写 http://localhost:8888/
2、不管是vuecli还是vite,同前缀代理是有前后顺序的,只生效前面的
比如当你调用 localhost:8080/api/other/getData
下面的写法会代理到 8888
'/api': 'http://localhost:8888',
'/api/other': 'http://localhost:88'
下面的写法会代理到 88
'/api/other': 'http://localhost:88',
'/api': 'http://localhost:8888'
接口调用
const REQUEST_PRE = '/api'
axios.get({
url: `${REQUEST_PRE}/getData`
}).then(res=>{
console.log(res)
})
nginx代理
现在大部分前端服务器都是用的nginx,如果是tomcat或是其他,需要让后端配置好代理前缀
nginx.conf的简单配置如下,代理只看server部分,如果有很多include需要问清楚还有没有其他公共前缀
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type text/html;
access_log logs/access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
server {
listen 80;
server_name localhost;
# 前端文件的地址,默认在nginx的html文件夹中找index.html
location / {
root html;
index index.html index.htm;
}
# 直接代理到域名
location /api/ {
proxy_pass https://www.baidu.com/;
}
# 代理前缀也可以加在域名上
location /req/ {
proxy_pass https://www.baidu.com/req/;
}
# nginx是全匹配,不会受前面的/req跟/api影响
location /req/api/ {
proxy_pass https://127.0.0.1:443/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
要特别小心location跟proxy_pass后面的反斜杠,写错了就是404。
如访问localhos:8080/api/getData时,
location /api ----这是错误的写法
实际上访问的是 https://www.baidu.com//getData —中间多了条反斜杠
location /api/
实际上访问的是 https://www.baidu.com/getData
proxy_pass https://www.baidu.com
实际上访问的是 https://www.baidu.com/api/getData
proxy_pass https://www.baidu.com/
实际上访问的是 https://www.baidu.com/getData
ps: 可刑的小知识
代理不是只是代理接口,也可以把页面直接代理到别人的网站去。那么如果你有一台内外网都可以访问的服务器的权限,你可以把公司内网的东西代理出去。
你还可以把自己的网站伪装成别人的网站,可以在nginx日志上看到别人的账号密码,所以这就是为什么前端密码传输最好要加密。
三、404问题定位
通过简单的了解vue的代理跟nginx的代理,那么正确的访问后端接口应该注意哪些呢?
1、前缀是不是要保留,本地pathRewrite写不写,nginx上的proxy_pass配置也要对应上
2、本地的前缀跟nginx的localtion是不是对应上了
3、看看有没有哪个缺心眼的少写了反斜杠
4、如果服务器用的不是nginx,你也可以询问一下后端的通用前缀是什么
5、post、get用没有写错,当然写错也可能是报405,要看后端怎么写
6、后端没部署或者链接给错这种问题,直接开喷就好了
四、关于Vue代理的前后顺序问题
不管是vite还是vuecli,查看源码发现都是用了http-proxy,而http-proxy是用Object.keys().map()来遍历配置项启动代理服务,并且没有见到前缀完整度比较,也就是说,前面的代理捕获到了,后面有没有更完整的代理前缀就不管了。
http-proxy部分源码如下,有兴趣的可以自己研究下完整源码
this.webPasses = Object.keys(web).map(function(pass) {
return web[pass];
});
ps:一开始直接看node_mouldes里面的vite代码,发现居然是打包后的(这也是vite更快的原因吧),还以为是vite自己写了个代理,去github下了源码,发现就是用了http-proxy,还是要 good good study