前言
因为新参加前端大哥在不到三个月之内就离职了,之前他担任的项目中还缺少了获奖名单的需求,正好我没活了就由我接手了。乍一看署理装备,好家伙,乱中麻(代码虽然能走通,但增加了后续保护的了解本钱)。
因为触及到 SSO 单点登录,需求域名才干正常登录(即恳求登录和用户信息的接口),因而需求在 nginx 服务器装备署理,导致了署理绕来绕去。
需求域名的原因:
由所以国际服,账号登录运用的是 SSO 单点登录,需求凭借 facebook, google 等登录接口(以 facebook 为例,即登录后 facebook 会回来 token 等用户信息),因为 facebook 规则凭借 SSO 单点登录时需求域名,因而团队中一般用的 ip 地址不能作为测验环境,而需求有域名的 nginx 服务器署理到测验环境,才干进行登录。
而在开发过程中,一般设置了登录逻辑,因而有必要经过登录(即成功发送登录恳求)才干执行其他操作(其他接口恳求,页面跳转等)。但因为后端那边的规划,把普通邮箱的登录也设置成了需求域名才干发送恳求,因而需求凭借 nginx 服务器署理到普通 ip 的测验环境。
正文
在本文中,普通测验地址为 10.10.13.187:8082/,带有域名的 nginx 服务器为 debug-test.example.com:59998/,后端接口 ip 地址分别为 登录接口 12.12.5.205:21301/,事务接口 12.12.5.205:21302/,上传接口 12.12.5.205:21303/
环境变量 env.js 的装备
关于环境变量,因为不同的环境需求不同的跳转链接,署理地址等等,即开发环境有开发环境相匹配的 env,镜像环境有镜像环境的 env,正式环境有正式环境的 env。
在咱们团队比较老的项目中,一般是这样布置的
// .env.development
NODE_ENV=development
VUE_APP_ENV=development
PUBLIC_PATH=/account
经过 process.env.VUE_APP_ENV
,拿到此刻的开发环境,再做相应的匹配,但这样做交给后端打包布置后,后端是无法看到 env 的装备的
而最新的项目中,则是放到 public 文件下,后端把项目打包后能够露出出来看到
// public/env.js
window.$$env = {}
// src/utils/env.ts
export const env = (window as any).$$env as Env;
axios 的装备
一开端的 axios 的装备
account.js
const instance = Axios.create({
baseURL: "https://" + env.baseUrl.login + "/",
});
instance.interceptors.request.use((config) => {
return intercepeReq(
env.baseUrl.login,
env.signature.secret
);
});
从这儿能够初略看出,baseURL 过于不合理,按理来说axios应该是由本地发送恳求的,但这儿竟然拼接了https成了一个网址,有点不符合认知。
interceptors
恳求阻拦部分,关于 intercepeReq
函数,是用于传签名的,但依照语义来看,命名应该是放入签名 signature 中的变量却放入了恳求根本途径 baseUrl 的变量当中,而且签名和根本途径竟然同用一个变量。
一开端的 env 装备
window.$$env = {
baseUrl: {
login: "debug-test.example.com:59998",
contribute: "debug-test.example.com:59998",
upload: "debug-test.example.com:59998",
},
signature: {
secret: "WAxxhxxa8afxxqaWTxxwyt8BxxBeQpHcTxxG6xxaknA=",
},
}
修改后的 axios 装备
const instance = Axios.create({
baseURL: env.baseUrl.account,
});
instance.interceptors.request.use((config) => {
return intercepeReq(
env.signature.backend,
env.signature.secret
);
});
修改后的 env 装备
window.$$env = {
baseUrl: {
account: "/account-web-sso",
createjam: "/1st-co-creation/createjam",
uploadFile: "/1st-co-creation/upload",
},
signature: {
secret: "WAxxhxxa8afxxqaWTxxwyt8BxxBeQpHcTxxG6xxaknA=",
backend: "debug-test.example.com:59998",
},
}
其间,因为恳求头设置了签名的原因,签名中包含了主机 host 即 signature 中的 backend,客户端宣布的网络恳求的主机host有必要与设置的签名的主机host相同,考虑到该项目因为登录权限有必要运用到域名,因而签名中的主机host设置一致设置为域名的测验环境主机host,而不是本地 ip 或许其他测验环境的。
一开端其他恳求的 axios 装备
contribute.js
const instance = Axios.create({
baseURL: "https://" + env.baseUrl.contribute + "/createjam/",
});
instance.interceptors.request.use((config) => {
return intercepeReq(
env.baseUrl.contribute,
env.signature.secret
);
});
upload.js
const instance = Axios.create({
baseURL: "https://" + env.baseUrl.upload + "/",
});
instance.interceptors.request.use((config) => {
return intercepeReq(
env.baseUrl.upload,
env.signature.secret
);
});
devServer 装备
一开端 devServer 的装备
【1】"/apis/v1/userinfo": {
target: "http://10.10.5.205:21301/",
changeOrigin: true,
},
【1】"/apis/v1/logout": {
target: "http://10.10.5.205:21301/",
changeOrigin: true,
},
【2】"/apis/v1/upload": {
target: "http://10.10.5.205:21303/",
changeOrigin: true,
},
【3】"/apis/": {
target: "http://10.10.5.205:21302/",
changeOrigin: true,
},
再结合 axios 的 各个接口恳求装备片段
// account.js
export function getUserinfo() {
return instance.get("/apis/v1/userinfo");
}
export function postLogout() {
return instance.get("/apis/v1/logout");
}
// contribute.js
export function contribute(path: string, data: ContributeData) {
return instance.post(`/apis/v1/works/submit/${path}`, data);
}
// upload.js
export function uploadFile (file: File) {
return instance.post(`/apis/v1/upload/anniversary`, file);
}
能够看出,每一个接口恳求都根本在 deServer
中装备了,然后其他特殊接口匹配不上就会匹配常用事务接口,难以区别出每个署理的意义,这真的对后续开发人员极其不友好(后续开发者要缕一遍逻辑才干知道这接口是衔接谁的)。从上述能够看出, account.js
中的 两个 /apis/v1/xxx
分别装备了两个,都是指向的同一个 ip 地址,这明显不太合适。
修改后
每个 devServer 的装备最好有个前缀,能够用 vue.config.js 中的 publicPath 的值,即标明晰这个接口是哪个项目的,而且一致,比方以 /1st-co-creation
为例。
结合 axios 中的 baseUrl 的值,署理前缀 /1st-co-creation
加上 baseUrl,再调配正则表达式对接口重写来恳求后端提供的接口地址。
而关于 devServer 的装备能够看这篇文章 白嫖即食:构建工具的proxy署理装备差异(处理跨域)
"/1st-co-creation/createjam": {
target: "http://10.10.5.205:21302/",
changeOrigin: true,
pathRewrite: {
"/1st-co-creation/createjam": "",
},
}
"/1st-co-creation/upload": {
target: "http://10.10.5.205:21303/",
changeOrigin: true,
pathRewrite: {
"/1st-co-creation/upload": "",
},
},
然后再说说通用接口,比方登录接口在事务中肯定有复用的,所以直接标明该接口的功能就行了。
"/account-web-sso": {
target: "http://10.10.5.205:21301/",
changeOrigin: true,
pathRewrite: {
"/account-web-sso": "",
},
},
聊到这儿,前端的署理根本聊完了,但最坑爹的便是触及到 SSO 单点登录需求域名,然后咱们就需求在 nginx 再做一层署理。所以也不能怪老哥,毕竟搁谁来也得蒙,我隔壁呆了好几年安卓转前端的哥也蒙。
nginx 的装备
而只需你敢用域名署理到本地(即 nginx 中【1】的署理,我就敢说它回来的便是一个 html 文档(整个文档是项目经过webpack打包之后放入署理后服务器中的),然后依据 html 文档里的js恳求途径,以此刻域名发送恳求,即你上面在 devServer 中的署理装备根本便是白费力气,因为它是以debug域名发送恳求的,而你的 devServer 署理装备是以署理后服务器恳求的。
【1】location /1st-co-creation/ {
proxy_pass http://10.10.13.187:8082/1st-co-creation/;
}
location /apis/v1/userinfo {
proxy_pass http://10.10.5.205:21301;
}
location /apis/v1/logout {
proxy_pass http://10.10.5.205:21301;
}
location /apis/v1/works/submit {
proxy_pass http://10.10.5.205:21302;
}
location /apis/v1/upload {
proxy_pass http://10.10.5.205:21303;
}
依然能够看到,犯得错误和 devServer 中的如出一辙,而且这儿是 nginx 的装备,许多需求用到debug的项目都会到这儿装备,所以标明是哪个项目非常重要,而且要留意不要污染了整个装备(即只需你用了整个署理姓名,其他人就不能用了)
其实nginx署理的装备和devServer署理的装备原理根本相同,都是匹配成功后把匹配后的字段往后接。 假如在 nginx 没有装备相应的署理或许没有匹配上,会回来 404
修改后的
location /1st-co-creation/ {
proxy_pass http://10.10.13.187:8082/1st-co-creation/;
}
location /1st-co-creation/createjam/ {
proxy_pass http://10.10.5.205:21301/;
}
location /account-web-sso/ {
proxy_pass http://10.10.5.205:21302/;
}
location /1st-co-creation/upload/ {
proxy_pass http://10.10.5.205:21303/;
}
看看就能够
因为以下设定,导致了客户端的 html 会进行缓存,而 js 或许 css 不会进行缓存,因而当你更新 env.js 时,不能对 env.js 进行删除和改动这两操作,因为当你更新 env.js 并上线后,此刻 env.js 是最新的,为了以防客户端拿到是缓存的(即老的html文件),这时 env.js 是最新的,老的 html 文件无法找到 env.js 中东西而导致报错。
server {
listen 80;
listen [::]:80;
server_name localhost;
access_log /var/log/nginx/host.access.log main;
location ~* \.(?:css|js)$ {
add_header Cache-Control "no-cache";
root /usr/share/nginx/html;
try_files $uri =404;
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
}
}
因为凭借了 nginx 服务器署理来启动项目,导致UI规划开发时不能热更新,需手动改写才干更新一次,但在规划UI时可运用本地,触及到接口时运用域名测验环境。
特典
因为在开发过程中,触及到了 cookie 相关的问题,即因为署理问题导致了后端没有给前端下发cookie,回来了401的错误
然后经此发现,我对 Cookie 除了简略的了解(它是一个类似于 session 的本地存储空间)外,其他竟一窍不通。
cookie
因为 HTTP 的恳求是无状态的,浏览器宣布的恳求后端服务器没办法区别用户的身份和信息。而浏览器每次发送恳求时都会在恳求头上带着 Cookie 。而 Cookie 会存储一些用户的信息,比方 token,sessionid(通话id),偏好设置等。
一般 Cookie 是由后端设置的,大致流程如下:
- 首次拜访网站时,浏览器发送恳求中并未带着 Cookie 。(类似于登录)
- 后端看到恳求中未带着 Cookie ,在 HTTP 的呼应头中参加
Set-Cookie
(里面放了 Cookie 的信息)回来给浏览器。 - 浏览器收到
Set-Cookie
后,会自动将 Cookie 保存下来。 - 之后拜访该网站时,HTTP 恳求头就会带着 Cookie,用户就不需求再次登录什么的了。
当然,也有由前端搜集,后端存储的,比方日夜间形式,语言等偏好设置由前端搜集好,发送恳求后带着上由后端存储和管理。
token恳求中呼应头set-Cookie
恳求中恳求头带着的cookie
留意:恳求头中带着的cookie是以key=value,“;”离隔的形式带着的。
而想要更直观的看,能够检查浏览器Network中的cookie选项
cookie中特点
特点 | 意义 |
---|---|
Name | Cookie的名称 |
Value | 对应名称的值 |
Domain | Cookie效果的域名 |
Path | Cookie收效的途径 |
Expires | 过期时刻,过了这个时刻后Cookie失效(详细的时刻日期) |
Max-age | 收效时刻,表明Cookie在多长时刻后失效(倒计时) |
Size | Cookie的长度,为name和value的长度和 |
HttpOnly | 避免经过JavaScript拜访Cookie(即在操控台中经过document.cookie读取,设置cookie) |
Secure | 只在HTTPS协议的情况下才会将Cookie传到后端(http达咩) |
SameSite | 是否允许跨站恳求时发送Cookie |
Partitioned | 第三方Cookie分区 |
Priority | 优先级 |
效果范围
Domain
设置 Cookie 效果的域名,即 Cookie 在哪个网站收效。比方后端在 Domain 中设置了 .juejin.cn
,那该 Cookie只能在这网站下收效。
Path
当咱们期望 Cookie 只在部分途径下收效,就能够运用Path进行约束。假如 path=/user
,相当于除了 .juejin.cn/user
这个路由途径下能运用设置的 Cookie 外,其他途径都不能运用。
.juejin.cn 能运用
.juejin.cn/user 能运用
.juejin.cn/user/2239042325059533 能运用
.juejin.cn/edior 不能运用
效果时刻
Session
假如Cookie的有效期为Session,类似于sessionStorge相同,即封闭浏览器就失效。
Expires
指定详细的失效时刻,格局大致为2025-02-17T04:44:56.921Z
,即到2025年2月17日4点44分56秒921毫秒
失效
Max-Age
从拿到 Cookie 后开端倒计时设置 的Max-Age的值。例如Max-age=3000
。当获取到该Cookie后开端倒计时,3000秒之后便失效。
Priority优先级
当Cookie的数量超过约束时,浏览器会铲除一部分Cookie。铲除哪些合适呢?Priority特点用来定义Cookie的优先级,低优先级的Cookie会优先被铲除。
Priority特点有三种: Low, Medium, High
其他的过于复杂或许在上述概括中大致说到的就不详细说了。