一文理清环境变量的使用与代理的管理
早在2020年就想写一篇类似的总结,但一直想的到没做到
这两天又遇到了此类问题,索性直接来一篇
项目里有env
、env.devlopment
env.prodction
等等文件,此类.env开头的文件统称为开发环境配置文件,目的是什么?目的是为了基于启动时所选择的环境来配置不同的地址或者数据(是的就是你心中所想的在package.json中配置的script项)
.env
优先级小于所有env.xxx
文件,也就是说在找不到所有类似文件的情况下.env会被最终解析
在vite项目中,可以控制台输出 import.meta.env
来获知当前所处的环境,webpack中其实也差不多,输出的语句不同罢了。
如何区分开发或者生产
项目执行运行本地服务器localhost
是在本地 npm run xxx
项目执行构建命令是在线上npm build xxx
env与proxy的关系:
举个例子
项目中,有时候要连接几个不常用的接口
假设我需要在项目中访问一个与后端不同的的接口,本质上是将跨域接口伪装成了本地接口以规避浏览器跨域问题, 它的地址可能是这样:http://www.wzdxcsk2.com/xxxx/yy
如何在项目中访问这个接口?它作为一个额外的接口,并不与后端接口一致
项目分为线上版与开发版本(万变不离其宗)两种。
为了保证我们可以在开发环境可以正确调用api,
脚手架通常会提供一个proxy对象,用以暂时屏蔽浏览器端的跨域问题
一个最简单的proxy:
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path: string) => path.replace(new RegExp(`^/api`), ''),
}
它的意思是说,如果遇到一个/api作为前缀的api接口,就将其转换为target指定的地址,
如:发出的请求应该是"http://jsonplaceholder.typicode.com/sayhi ",而在定义接口的时候应该用"/api/sayhi",这样脚手架在捕获到这个接口时,就会将其转换成"localhost:port/api/sayhi",但只是伪装,本质上也只是为了欺骗
浏览器的跨域机制用于开发
线上环境若需要访问不属于后端的接口,则需要接口提供方提供跨域支持,因为前端在线上其实也仅仅是一个个静态资源,这时候就得需要接口服务端在他们的代码中允许访问跨域请求
BOOM
有了这么多前置知识,接下来就可以理清环境变量与env在日常环境中的配合使用了
假设有这样一个外来接口http://jsonplaceholder.typicode.com/define/problem
需要调用,
在此可以提供一个基础范式:不保证完全优雅,但保证可用
前面说过了env开发与线上的区别,对此,我们可以分别在env的不同环境配置相同的数据:
# env开发环境下:
# env.development
VITE_API_URL_PREFIX_YY=/WZDXCSK
# env生产环境下:
# env.produect
VITE_API_URL_PREFIX_YY=http://jsonplaceholder.typicode.com
而我们在定义接口时,则需要使用import.meta.env.VITE_API_URL_PREFIX_YY
来确定此刻的接口究竟是什么,如果以上述配置来看,假设fetch接口为http://jsonplaceholder.typicode.com/define/problem
则开发时import.meta.env.VITE_API_URL_PREFIX_YY + '/define/problem'
url为:/WZDXCSK/define/problem
则生产时import.meta.env.VITE_API_URL_PREFIX_YY + '/define/problem'
url为:http://jsonplaceholder.typicode.com/define/problem
是的也许会很疑惑:开发时的接口全路径为/WZDXCSK/define/problem
,这并不是一个完整的合法的api,是的,但是由于是在开发环境,而我们则可以使用脚手架下的proxy来规避这个问题:
//脚手架的配置文件 config.js
proxy:{
//以上述为例,开发环境下import.meta.env.VITE_API_URL_PREFIX_YY被统一替换成了/WZDXCSK,那么我们直接对其代理转换即可
'/WZDXCSK':{
target:'http://jsonplaceholder.typicode.com' //将指定的前缀替换成真正的api接口
rewrite: (path: string) => path.replace(new RegExp(`^/WZDXCSK`), ''), // 将匹配完毕后将原本的替换成空,因为'/WZDXCSK'是我们臆想出来的
changeOrigin: true,// 是否跨域
}
}
值得一提的是,proxy只允许开发环境下使用,这是为了方便开发者,而在生产环境下则需要后端开发者配置允许跨域,
换句话说,开发环境下的跨域FE可以自己解决,线上环境下的跨域则需要BE处理:
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
👆:生产环境下以上报错须后端解决。
总结一下:
通过使用env文件我们可以自由定义api地址。其实我们可以定义的还有很多,总而言之,env是一个比较大的条件文件
以上。