UniApp开发深度解析:跨域问题、路径配置与代理策略

UniApp 开发配置详解:baseUrlmanifest.json 与路径设计

在开发 UniApp 项目的过程中,配置开发环境的路径一直是个容易踩坑的地方,比如设置 baseUrl、调试环境路径 /pawlapi,以及为什么直接写 localhost 不行却必须通过 manifest.json 中的代理转发实现?这篇文章将通过代码实例和原理分析,深入讲解 路径设计、开发与生产环境配置的逻辑,并解答为什么这些操作是必要的。


1️⃣ 配置设计目的:为何需要区分路径?

问题背景

UniApp 项目中,前端代码需要向后端发起请求获取数据。而开发和生产环境下的后端路径通常不同:

  1. 开发环境:在本地调试时,后端服务跑在 localhost 或公司内网 IP 上(如 192.168.x.x)。
  2. 生产环境:实际用户访问时,后端服务通常运行在域名或正式服务器上。

为什么直接写 localhost 不行?

直接在前端代码中写 localhost192.168.x.x 是不行的,因为:

  1. 跨域问题:浏览器对跨域请求有限制,localhost:8085localhost:8080 被认为是不同的来源(不同端口视为不同域),需要通过代理转发。
  2. 多平台兼容:UniApp 不止运行在 H5,还可能打包成 App 或小程序。如果硬编码为 localhost,在非浏览器环境下就完全不可用。

2️⃣ 环境配置的设计逻辑

在代码中看到的这段配置:

var baseURL = '', basePrintURL = '', baseAndonURL = '';

// uEnvDev: 开发环境
if (process.env.NODE_ENV === 'development') {
    // 针对 H5 环境
	// #ifdef H5
	   baseURL = "/pawlapi";
	   basePrintURL = '/print';
	   baseAndonURL = '/andon';
	// #endif
	// 针对 App 或小程序
	// #ifdef APP-PLUS || MP
	   baseURL = "http://192.168.100.89:8080/pawl";
	   basePrintURL = 'http://192.168.2.39:8090/mps';
	   baseAndonURL = 'http://192.168.2.132:8081/adxt';
	// #endif
}

1. 开发环境 (development)

H5 环境:
  • baseURL = "/pawlapi":这里使用了一个相对路径 /pawlapi,看似简单,但实际上是通过开发工具的 代理转发 功能将它映射到后端地址。
  • 代理配置(通常在 manifest.jsonvite.config.js 中定义):
    proxy: {
        '/pawlapi': {
            target: 'http://192.168.100.89:8080/pawl', // 后端真实服务地址
            changeOrigin: true,
            pathRewrite: { '^/pawlapi': '' } // 去掉 '/pawlapi' 前缀
        }
    }
    
    • 作用:前端请求 /pawlapi/api/FhdApi/getFhdDetail,代理转发会将其转化为 http://192.168.100.89:8080/pawl/api/FhdApi/getFhdDetail
    • 原因:跨域问题!通过开发工具代理,前端可以绕过浏览器的同源限制。
App 和小程序环境:
  • 这里直接写了后端内网地址 http://192.168.100.89:8080/pawl,因为在这些环境下不存在跨域问题。
  • 路径选择逻辑
    // #ifdef APP-PLUS || MP
    baseURL = "http://192.168.100.89:8080/pawl";
    
    • 当项目运行在 App 或小程序上时,直接访问后端服务器。

2. 生产环境 (production)

在生产环境中,代码中会切换到正式的后端地址:

if (process.env.NODE_ENV === 'production') {
    // 针对 H5 环境
	// #ifdef H5
	   baseURL = "/pawlapi"; // 通过 Nginx 或 Web 服务器处理转发
	// #endif
	// 针对 App 或小程序
	// #ifdef APP-PLUS || MP
	   baseURL = "http://production-server.com/pawl"; // 正式后端地址
	// #endif
}

在生产环境中,代理转发通常由 Nginx 或其他服务器代理完成。例如:

server {
    location /pawlapi {
        proxy_pass http://production-server.com/pawl;
        proxy_set_header Host $host;
    }
}

3️⃣ 为什么必须改 manifest.json 配置?

原因分析

之前尝试直接在代码中将 baseURL 改为 http://localhost:8080/pawl,但发现不生效。原因是:

  1. 代理冲突:开发环境的 H5 模式依赖于 manifest.jsonvite.config.js 中的代理配置。如果代码中写死 localhost,就跳过了代理机制,导致请求被浏览器阻止。
  2. 跨域限制:直接访问 localhost:8080 会触发跨域问题,浏览器拒绝请求。

正确的做法

通过修改 manifest.json,将代理配置为后端的实际路径:

"network": {
    "proxy": {
        "/pawlapi": {
            "target": "http://192.168.100.89:8080/pawl",
            "changeOrigin": true,
            "pathRewrite": {
                "^/pawlapi": ""
            }
        }
    }
}

这样前端代码保持使用 /pawlapi,由代理完成路径转发,解决跨域问题。


4️⃣ 请求函数的设计与路径判断逻辑

核心代码分析

if (options.url.indexOf('1') === 0) {
    options.url = this.config.basePrintURL + options.url.substr(1);
} else if (options.url.indexOf('2') === 0) {
    options.url = this.config.baseAndonURL + options.url.substr(1);
} else {
    options.url = this.config.baseUrl + options.url;
}
逻辑解读:
  1. 如果 URL 以 1 开头,说明需要请求 打印服务,所以拼接 basePrintURL
  2. 如果 URL 以 2 开头,说明请求的是 安灯系统,所以拼接 baseAndonURL
  3. 默认情况下,拼接 baseUrl,即通常的后端服务路径。

设计的目的

  • 分模块管理:不同的业务请求可以灵活地指向不同的后端服务(打印、安灯等)。
  • 统一配置:通过 baseUrl 等集中管理,避免在每个请求中重复写路径,便于后期维护。

🌐 读懂 Proxy(代理配置)!

你是不是跟我一样,当初看到“Proxy(代理)配置”时一头雾水?特别是写前端项目的时候,总是听到“跨域问题”“代理转发”“manifest.json配置路径”这些名词,然后被搞得晕头转向!今儿就讲讲什么是 代理配置(Proxy),以及为什么开发环境必须用它。💡


1️⃣ 什么是 Proxy(代理)?

现实世界的代理是什么?

打个比方:

  • 你想去一个图书馆借书,但你没有会员卡(权限不足)。
  • 你找到一个熟人,他愿意帮你借书(代理)。
  • 你把书名告诉他,熟人用他的会员卡把书借给你(请求转发)。

在这个例子中:

  1. :前端项目
  2. 图书馆:后端服务器
  3. 熟人:代理服务
  4. 借书:请求数据

代理的作用就是在你和图书馆(前端和后端)之间搭建一个桥梁,帮助你完成无法直接完成的事情。


技术世界里的代理是什么?

在前端开发中,代理主要用来解决跨域问题。当前端(H5)请求后端接口时,如果前后端的域名或端口不同,就会触发浏览器的安全机制(同源策略),请求被拦截(就像你没有会员卡进不了图书馆)。


2️⃣ 为什么需要 Proxy?(跨域问题的简单解释)

什么是跨域?

浏览器有个“同源策略”,规定前端页面和后端接口必须是“同源”的,只有这样才能正常通信。

“同源”要求三点:

  1. 协议相同(如 http://https://
  2. 域名相同(如 localhostexample.com
  3. 端口相同(如 80808081
例子:
  • http://localhost:8080http://localhost:8080/api:同源!
  • http://localhost:8080http://192.168.1.1:8080/api:跨域!
  • http://localhost:8080http://localhost:8081/api:跨域!

当我们在开发环境中:

  • 前端运行在 http://localhost:8085
  • 后端运行在 http://localhost:8080 由于端口不同,属于“跨域”,请求会被浏览器拦截。

代理如何解决跨域?

代理就是一个“中间人”,它伪装成后端,把前端的请求转发给后端。

例子:
  1. 前端发送请求:http://localhost:8085/api/login
  2. 代理接收到请求,把它转发到后端:http://localhost:8080/api/login
  3. 后端返回数据,代理再把数据转发给前端。

通过代理,前端就“以为”请求的是同一个服务器,跨域问题就解决了!


3️⃣ UniApp 中的 Proxy 配置(开发环境调试利器)

问题回顾:为什么直接写 localhost 不行?

在 UniApp 项目中,如果直接写 baseURL = "http://localhost:8080/pawl",会有两个问题:

  1. 跨域问题:浏览器拦截请求。
  2. 多平台兼容问题
    • H5 模式中,浏览器会拦截跨域请求。
    • App 或小程序环境中没有跨域问题,但你直接写 localhost,其他设备就访问不了(如你的手机无法访问电脑的 localhost)。

所以,我们需要用 代理配置 来解决这些问题。


关键代码:开发环境路径配置

// 配置开发环境下的地址
if (process.env.NODE_ENV === 'development') {
    // H5 环境
	// #ifdef H5
	   baseURL = "/pawlapi"; // 使用代理转发
	// #endif

	// App 和小程序环境
	// #ifdef APP-PLUS || MP
	   baseURL = "http://192.168.100.89:8080/pawl"; // 直接访问后端
	// #endif
}
H5 环境中 /pawlapi 的作用:
  1. /pawlapi 是个 虚拟路径,它不会直接访问真实后端。
  2. 通过开发工具(如 Webpack、Vite)的代理功能,将 /pawlapi 转发到后端 http://localhost:8080/pawl

Proxy 配置在 manifest.json 或 vite.config.js

manifest.json 配置
"network": {
    "proxy": {
        "/pawlapi": {
            "target": "http://192.168.100.89:8080/pawl", // 后端实际路径
            "changeOrigin": true, // 改变请求来源(伪装成后端)
            "pathRewrite": {
                "^/pawlapi": "" // 去掉 /pawlapi 前缀
            }
        }
    }
}
Vite 配置
export default {
  server: {
    proxy: {
      '/pawlapi': {
        target: 'http://192.168.100.89:8080/pawl',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/pawlapi/, '') // 去掉前缀
      }
    }
  }
};

4️⃣ Proxy 的应用与调试过程

1. 修改路径时踩过的坑

问题:为什么直接用 localhost 不行?

  • 如果直接写 http://localhost:8080/pawl,浏览器会触发跨域限制。
  • 必须通过代理将 /pawlapi 转发到 http://localhost:8080/pawl

问题:为什么 App 上不用代理?

  • App 和小程序环境没有跨域问题,可以直接访问后端。

2. 使用 Proxy 的调试过程

  1. 验证代理是否生效

    • 检查前端请求的地址是否是 /pawlapi
    • 查看代理是否正确转发到了 http://localhost:8080/pawl
  2. 配置问题排查

    • 确保代理配置中的路径正确。
    • 如果代理不生效,检查是否忘了重启开发服务。

5️⃣ 其他开发环境配置与最佳实践

路径的动态配置

前后端通信的路径通过环境变量动态切换,避免硬编码:

const baseURL = process.env.NODE_ENV === 'production'
    ? 'http://production-server.com/pawl' // 生产环境地址
    : '/pawlapi'; // 开发环境地址

路径判断逻辑

通过路径的开头字符区分不同服务:

if (options.url.indexOf('1') === 0) {
    options.url = this.config.basePrintURL + options.url.substr(1); // 打印服务
} else if (options.url.indexOf('2') === 0) {
    options.url = this.config.baseAndonURL + options.url.substr(1); // 安灯服务
} else {
    options.url = this.config.baseUrl + options.url; // 默认服务
}

🌐 为什么需要跨域隔离?一文带你搞懂跨域背后的秘密!

🚪 开篇问题:为什么要跨域隔离?

在学习前端时,我们常听到“跨域”这个词,而“跨域隔离”则是浏览器中的一个核心机制。很多开发者可能觉得它很麻烦——要配置代理、调整服务器响应、绕过各种限制等等。但是,你有没有想过:为什么跨域隔离这么重要?没有它会发生什么?

本文将从通俗比喻专业解析,帮你全面理解跨域隔离的意义原因


1️⃣ 跨域隔离是什么?

什么是“同源策略”?

跨域隔离的基础是浏览器中的“同源策略(Same-Origin Policy)”。它是一种安全机制,用来限制一个网页的脚本只能访问与其同源的资源。

“同源”规则:

  • 协议相同(httphttps
  • 域名相同(example.com
  • 端口相同(8080

举个栗子:

  • 同源: http://example.com:8080http://example.com:8080 是同源的。
  • 跨域: http://example.com:8080https://example.com:8080 是跨域的,因为协议不同。

跨域隔离的作用:

跨域隔离是为了保护用户的数据安全。它防止一个恶意网站偷偷获取或篡改其他网站的资源和数据。


2️⃣ 为什么需要跨域隔离?(通俗解释)

生活中的比喻:

🏢 比喻:不同公司的隔离门禁

想象一下,你在公司 A 的办公大楼工作。这栋大楼有严密的门禁系统,只有公司 A 的员工可以进入。

突然,公司 B 的员工想偷偷溜进公司 A 的大楼窃取重要文件。这时,门禁系统会阻止公司 B 的员工,因为他没有公司 A 的员工卡。

在这个例子中:

  • 公司 A 的大楼:一个网站(http://example.com
  • 公司 B 的员工:另一个网站的脚本(http://malicious-site.com
  • 门禁系统:跨域隔离机制

如果没有隔离会怎样?

假设没有门禁系统(没有跨域隔离),公司 B 的员工可以轻松进入公司 A,窃取敏感信息,甚至破坏系统。

在技术世界中,没有跨域隔离可能会导致:

  1. 用户隐私泄露:恶意网站窃取用户的 Cookies 和身份信息。
  2. 篡改资源:第三方脚本可以更改其他网站的内容或行为。
  3. 安全漏洞:攻击者利用漏洞劫持用户的会话。

3️⃣ 技术中的跨域隔离

1. 防止 XSS 攻击(跨站脚本攻击)

问题:什么是 XSS? 跨站脚本攻击(XSS,Cross-Site Scripting)是指攻击者通过向网页注入恶意代码,利用网页对用户执行恶意操作。

例子:

假设你登录了银行网站(https://bank.com),它通过 Cookies 保存了你的登录状态。此时,一个恶意网站(https://malicious.com)偷偷加载了一个脚本:

fetch('https://bank.com/api/getUserInfo', {
  credentials: 'include'
}).then(response => response.json()).then(data => {
  console.log(data); // 恶意网站拿到了你的银行账户信息
});

如果没有跨域隔离,恶意网站就能窃取你的账户信息!

解决方法:

跨域隔离可以阻止这个脚本访问 https://bank.com 的资源,从而保护用户的隐私和数据安全。


2. 防止 CSRF 攻击(跨站请求伪造)

问题:什么是 CSRF? 跨站请求伪造(CSRF,Cross-Site Request Forgery)是指攻击者利用用户的身份,在用户不知情的情况下伪造请求,执行一些恶意操作。

例子:
  • 你登录了购物网站(https://shop.com),并保存了登录状态。
  • 一个恶意网站(https://evil.com)引诱你点击了一个按钮。
  • 这个按钮发起了一个 POST 请求,偷偷帮你购买了一个昂贵的商品。
解决方法:

跨域隔离可以确保 https://evil.com 无法直接向 https://shop.com 发起请求。


4️⃣ 为什么跨域问题只在浏览器中存在?

1. 浏览器的“安全性”设计

跨域隔离是浏览器特有的安全机制,目的是保护用户在浏览器中访问多个网站时的数据不被互相干扰。

服务器端没有跨域问题,因为后端之间的通信通常没有同源策略的限制。

2. 用户数据的重要性

浏览器中保存了大量用户隐私数据,比如:

  • Cookies(存储登录状态)
  • 本地存储(Local Storage / Session Storage)
  • 缓存文件

跨域隔离是为了防止恶意网站读取这些敏感信息。


5️⃣ 跨域隔离的挑战与解决方案

问题:跨域隔离限制了合法操作

虽然跨域隔离保护了安全,但它也对前后端分离的开发模式带来了麻烦。例如:

  • 前端运行在 http://localhost:8080
  • 后端运行在 http://localhost:3000

由于跨域隔离,前端无法直接请求后端的接口。

解决方案:通过代理实现跨域通信

方法 1:前端代理(Proxy)

在开发环境中,前端可以通过代理转发请求,从而绕过跨域限制。

proxy: {
  '/api': {
    target: 'http://localhost:3000', // 后端地址
    changeOrigin: true, // 改变请求来源
    pathRewrite: { '^/api': '' } // 重写路径
  }
}
方法 2:后端处理 CORS

后端可以通过设置 CORS(跨域资源共享)头部,允许特定的前端访问:

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

6️⃣ UniApp 中的跨域问题与解决方法

1. H5 模式下的跨域

在 H5 环境中,我们通过代理解决跨域问题。比如,在开发环境中,我们使用 baseURL = '/pawlapi',通过 Webpack 或 Vite 配置代理,将其转发到真实的后端路径。

关键代码:
proxy: {
  '/pawlapi': {
    target: 'http://localhost:8080/pawl',
    changeOrigin: true,
    rewrite: (path) => path.replace(/^\/pawlapi/, '')
  }
}

2. App 和小程序环境没有跨域问题

在 App 和小程序中,跨域问题不存在,因为这些平台不依赖浏览器的同源策略。你可以直接访问后端接口,比如:

baseURL = "http://192.168.100.89:8080/pawl";

7️⃣ 总结

为什么要跨域隔离?

  1. 保护用户隐私:防止恶意网站窃取 Cookies、本地存储和其他敏感数据。
  2. 防止安全攻击:避免 XSS、CSRF 等常见的跨站攻击。
  3. 限制资源访问:确保网站之间的资源和数据不能被随意篡改或利用。

跨域隔离的现实意义

就像在生活中,公司之间必须隔离门禁,网络世界中的跨域隔离是保障互联网安全的重要基础。虽然它会带来一些开发上的复杂性,但通过代理和 CORS,我们完全可以优雅地应对这些挑战!

一句话总结:跨域隔离看似麻烦,其实是互联网安全的守护者!✨