前端开发常见坑处理
各种环境需要的地址类的处理
- .env 文件
# 新建
# .env.development 、 .env.production 、 .env.test
# 主站API地址
VITE_APP_API=/api
# 文件服务地址
VITE_FILE_API=/oss/file
- 环境变量读取工具类
/**
* 获取环境变量
*/
export const getEnvByKey = (key: string) => {
const val = window.SITE_CONFIG?.[key] || import.meta.env[key];
if (val) {
return val;
} else {
console.warn(SITE_CONFIG);
throw new Error("未找到环境变量");
}
};
- nginx 运时时外部修改
#!/bin/bash
cat > /usr/share/nginx/html/env.js <<EOF
window.SITE_CONFIG = {
VITE_APP_API: "${VITE_APP_API:-/api}",
VITE_FILE_API: "${VITE_FILE_API:-https://smart.saas.vppark.cn/file}",
VITE_VISITOR_URL: "${VITE_VISITOR_URL:-https://smart-home.saas.vppark.cn/h5}"
};
EOF
cp -r /tmp/icon/* /home/upload_file
nginx -g 'daemon off;'
- index.html
<script src="./env.js"></script>
<script>
//全局钩子
window.SITE_CONFIG = {
//api
apiURL: "<%=apiURL%>",
...window.SITE_CONFIG
};
</script>
内网图片、协议不一致处理
https不能调用http,后端返回的内网图片不能正常显示,开发环境https证书错误无法加载
1、修改代码处理图片路径走内网代理
/** 内网 / 第三方图片走同源反代,避免混合内容与跨域问题 */
export const INTRANET_IMAGE_PROXY_PREFIX = "/intranet-image-proxy";
/**
* 与 nginx default.conf 的 intranet-image-proxy location 正则保持一致:
* host 必须是 10.x.x.x / 172.x.x.x / 192.x.x.x(可带端口)。
* nginx 只放行这三段,这里不匹配就走原地址,避免拼出 nginx 404 的代理路径。
*/
const INTRANET_HOST_PATTERN = /^(?:10|172|192)\.\d+\.\d+\.\d+(?::\d+)?$/;
/**
* 内网 IP 的 http(s) 全路径图片包一层 /intranet-image-proxy/;
* 其余(空值、相对路径、外网地址)原样返回。
*/
export function toInternetImage(src: string) {
// 空、null、undefined、纯空白:返回空串
const raw = String(src ?? "").trim();
if (!raw) {
return raw;
}
// 协议相对地址(//10.1.2.3:6120/a.jpg)补全 http:
let url = raw;
if (url.startsWith("//")) {
url = `http:${url}`;
}
// 相对路径或其他协议不是全路径,不处理
if (!/^https?:\/\//i.test(url)) {
return raw;
}
// host 不是 10/172/192 段的内网 IP 不处理,规则与 nginx 放行一致
const host = new URL(url).host;
if (!INTRANET_HOST_PATTERN.test(host)) {
return raw;
}
// 内网全路径:包一层同源代理,规避混合内容拦截
return `${location.origin}${INTRANET_IMAGE_PROXY_PREFIX}/${url}`;
}
2、增加nginx图片代理配置
# 顶层区块
map $http_x_forwarded_proto $origin_scheme {
default $http_x_forwarded_proto;
"" $scheme;
}
# 加在内网代理目标地址:从原始请求行($request_uri server是客户端发来的原文)提取,
# 内嵌地址 http://10.x... 里的 // 不受归一化影响;白名单(10/172/192 段)由这里的正则把守,
# 未命中时变量为空,location 里显式 404
map $request_uri $intranet_target {
~^/intranet-image-proxy/(https?://(?:10|172|192)\.\d+\.\d+\.\d+(?::\d+)?/.*)$ $1;
}
# 内网代理目标 host(proxy_set_header Host 用,与目标地址分开抓)
map $request_uri $intranet_target_host {
~^/intranet-image-proxy/https?://((?:10|172|192)\.\d+\.\d+\.\d+(?::\d+)?)/ $1;
}
# location 区块下
merge_slashes off;
# 内网图片代理(设备抓拍等内网 http/https 图片统一走这里)
# 归一化会把 URI 里内嵌地址 http://10.x... 的 // 合并掉,proxy_redirect 改写 301 保持同源)所以 location ~只做前缀匹配,
^# 目标地址从 $request_uri 原文经 map 提取,proxy_pass 变量式原样转发,// 不被动过
location /intranet-image-proxy/(?<upstream_scheme>https?)://(?<upstream_host>(10|172|192)\.\d+\.\d+\.\d+(?::\d+)?)(?<upstream_path>/.*)$ {
# 未命中白名单(map 没抓到目标地址)直接 404
if ($intranet_target = "") { return 404; }
proxy_pass $upstream_scheme://$upstream_host$upstream_path$is_args$args;intranet_target;
proxy_set_header Host $upstream_host;intranet_target_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_ssl_verify off;
# 处理上有游返回的重定向,避免跳转到内网地址;改写出的地址同样带内嵌 //,
# 浏览器跟随重定向的二次请求仍走上面的 map 提取,链路闭环
proxy_redirect ~^(?<redirect_scheme>https?)://(?<redirect_host>(?:10|172|192)\.\d+\.\d+\.\d+(?::\d+)?)(?<redirect_path>/.*)$ $origin_scheme://$http_host/intranet-image-proxy/$redirect_scheme://$redirect_host$redirect_path;
}