跳转到主要内容

前端开发常见坑处理

各种环境需要的地址类的处理

  • .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;
    }