UniApp开发深度解析:跨域问题、路径配置与代理策略
UniApp 开发配置详解:baseUrl
、manifest.json
与路径设计
在开发 UniApp 项目的过程中,配置开发环境的路径一直是个容易踩坑的地方,比如设置 baseUrl
、调试环境路径 /pawlapi
,以及为什么直接写 localhost
不行却必须通过 manifest.json
中的代理转发实现?这篇文章将通过代码实例和原理分析,深入讲解 路径设计、开发与生产环境配置的逻辑,并解答为什么这些操作是必要的。
1️⃣ 配置设计目的:为何需要区分路径?
问题背景
UniApp 项目中,前端代码需要向后端发起请求获取数据。而开发和生产环境下的后端路径通常不同:
-
开发环境:在本地调试时,后端服务跑在
localhost
或公司内网 IP 上(如192.168.x.x
)。 - 生产环境:实际用户访问时,后端服务通常运行在域名或正式服务器上。
为什么直接写 localhost
不行?
直接在前端代码中写 localhost
或 192.168.x.x
是不行的,因为:
-
跨域问题:浏览器对跨域请求有限制,
localhost:8085
和localhost:8080
被认为是不同的来源(不同端口视为不同域),需要通过代理转发。 -
多平台兼容: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.json
或vite.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
,但发现不生效。原因是:
-
代理冲突:开发环境的 H5 模式依赖于
manifest.json
或vite.config.js
中的代理配置。如果代码中写死localhost
,就跳过了代理机制,导致请求被浏览器阻止。 -
跨域限制:直接访问
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;
}
逻辑解读:
- 如果 URL 以
1
开头,说明需要请求 打印服务,所以拼接basePrintURL
。 - 如果 URL 以
2
开头,说明请求的是 安灯系统,所以拼接baseAndonURL
。 - 默认情况下,拼接
baseUrl
,即通常的后端服务路径。
设计的目的
- 分模块管理:不同的业务请求可以灵活地指向不同的后端服务(打印、安灯等)。
-
统一配置:通过
baseUrl
等集中管理,避免在每个请求中重复写路径,便于后期维护。
🌐 读懂 Proxy(代理配置)!
你是不是跟我一样,当初看到“Proxy(代理)配置”时一头雾水?特别是写前端项目的时候,总是听到“跨域问题”“代理转发”“manifest.json配置路径”这些名词,然后被搞得晕头转向!今儿就讲讲什么是 代理配置(Proxy),以及为什么开发环境必须用它。💡
1️⃣ 什么是 Proxy(代理)?
现实世界的代理是什么?
打个比方:
- 你想去一个图书馆借书,但你没有会员卡(权限不足)。
- 你找到一个熟人,他愿意帮你借书(代理)。
- 你把书名告诉他,熟人用他的会员卡把书借给你(请求转发)。
在这个例子中:
- 你:前端项目
- 图书馆:后端服务器
- 熟人:代理服务
- 借书:请求数据
代理的作用就是在你和图书馆(前端和后端)之间搭建一个桥梁,帮助你完成无法直接完成的事情。
技术世界里的代理是什么?
在前端开发中,代理主要用来解决跨域问题。当前端(H5)请求后端接口时,如果前后端的域名或端口不同,就会触发浏览器的安全机制(同源策略),请求被拦截(就像你没有会员卡进不了图书馆)。
2️⃣ 为什么需要 Proxy?(跨域问题的简单解释)
什么是跨域?
浏览器有个“同源策略”,规定前端页面和后端接口必须是“同源”的,只有这样才能正常通信。
“同源”要求三点:
- 协议相同(如
http://
或https://
) - 域名相同(如
localhost
、example.com
) - 端口相同(如
8080
、8081
)
例子:
- ✅
http://localhost:8080
和http://localhost:8080/api
:同源! - ❌
http://localhost:8080
和http://192.168.1.1:8080/api
:跨域! - ❌
http://localhost:8080
和http://localhost:8081/api
:跨域!
当我们在开发环境中:
- 前端运行在
http://localhost:8085
- 后端运行在
http://localhost:8080
由于端口不同,属于“跨域”,请求会被浏览器拦截。
代理如何解决跨域?
代理就是一个“中间人”,它伪装成后端,把前端的请求转发给后端。
例子:
- 前端发送请求:
http://localhost:8085/api/login
- 代理接收到请求,把它转发到后端:
http://localhost:8080/api/login
- 后端返回数据,代理再把数据转发给前端。
通过代理,前端就“以为”请求的是同一个服务器,跨域问题就解决了!
3️⃣ UniApp 中的 Proxy 配置(开发环境调试利器)
问题回顾:为什么直接写 localhost
不行?
在 UniApp 项目中,如果直接写 baseURL = "http://localhost:8080/pawl"
,会有两个问题:
- 跨域问题:浏览器拦截请求。
-
多平台兼容问题:
- 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
的作用:
-
/pawlapi
是个 虚拟路径,它不会直接访问真实后端。 - 通过开发工具(如 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 的调试过程
-
验证代理是否生效
- 检查前端请求的地址是否是
/pawlapi
。 - 查看代理是否正确转发到了
http://localhost:8080/pawl
。
- 检查前端请求的地址是否是
-
配置问题排查
- 确保代理配置中的路径正确。
- 如果代理不生效,检查是否忘了重启开发服务。
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)”。它是一种安全机制,用来限制一个网页的脚本只能访问与其同源的资源。
“同源”规则:
- 协议相同(
http
或https
)- 域名相同(
example.com
)- 端口相同(
8080
)
举个栗子:
-
同源:
http://example.com:8080
和http://example.com:8080
是同源的。 -
跨域:
http://example.com:8080
和https://example.com:8080
是跨域的,因为协议不同。
跨域隔离的作用:
跨域隔离是为了保护用户的数据安全。它防止一个恶意网站偷偷获取或篡改其他网站的资源和数据。
2️⃣ 为什么需要跨域隔离?(通俗解释)
生活中的比喻:
🏢 比喻:不同公司的隔离门禁
想象一下,你在公司 A 的办公大楼工作。这栋大楼有严密的门禁系统,只有公司 A 的员工可以进入。
突然,公司 B 的员工想偷偷溜进公司 A 的大楼窃取重要文件。这时,门禁系统会阻止公司 B 的员工,因为他没有公司 A 的员工卡。
在这个例子中:
-
公司 A 的大楼:一个网站(
http://example.com
) -
公司 B 的员工:另一个网站的脚本(
http://malicious-site.com
) - 门禁系统:跨域隔离机制
如果没有隔离会怎样?
假设没有门禁系统(没有跨域隔离),公司 B 的员工可以轻松进入公司 A,窃取敏感信息,甚至破坏系统。
在技术世界中,没有跨域隔离可能会导致:
- 用户隐私泄露:恶意网站窃取用户的 Cookies 和身份信息。
- 篡改资源:第三方脚本可以更改其他网站的内容或行为。
- 安全漏洞:攻击者利用漏洞劫持用户的会话。
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️⃣ 总结
为什么要跨域隔离?
- 保护用户隐私:防止恶意网站窃取 Cookies、本地存储和其他敏感数据。
- 防止安全攻击:避免 XSS、CSRF 等常见的跨站攻击。
- 限制资源访问:确保网站之间的资源和数据不能被随意篡改或利用。
跨域隔离的现实意义
就像在生活中,公司之间必须隔离门禁,网络世界中的跨域隔离是保障互联网安全的重要基础。虽然它会带来一些开发上的复杂性,但通过代理和 CORS,我们完全可以优雅地应对这些挑战!
一句话总结:跨域隔离看似麻烦,其实是互联网安全的守护者!✨