前言:
在项目开发中,跨域算是常见的问题了,前端来解决跨域也是有多种方式,比如常见的proxy, uniapp的配置里面也有同样的方法,但是最近我遇到一个很奇怪的问题,不知道是服务端网关限制的原因还是别的原因,就是前端用proxy解决跨域后,接口一直处于pending状态,走不到服务端,所以我使用了nginx来实现跨域解决。这里整理下方法。
跨域问题的产生原因:
指一个页面尝试加载来自跨域(协议、域名、端口)的资源时所遇到的限制和问题,比如:ip/端口不同,产生了跨域问题
小程序与uniapp的内置浏览器无跨域问题:
UniApp 的内置浏览器是基于 WebView 封装的运行环境,默认禁用同源策略
小程序运行在微信/支付宝等平台的沙盒环境中,所有网络请求由客户端原生代码代理,实际请求由平台客户端发出,而非网页浏览器
小程序还有白名单机制:
开发者需在后台配置合法域名(如request 合法域名列表
),平台会自动处理跨域问题,对外表现为"无跨域限制"
特性 | 浏览器 | UniApp 内置浏览器/小程序 |
---|---|---|
请求发起方 | 浏览器 JavaScript 引擎 | 原生 WebView/客户端环境 |
网络栈 | 浏览器网络层 | 原生网络模块(Android/iOS 原生代码) |
同源策略应用 | 严格强制执行 | 默认禁用或由平台代理绕过 |
实际请求地址 | 直接显示目标 URL | 通过客户端代理,隐藏真实端点 |
CORS 检查 | 是 | 否 |
跨域问题前端解决方法:
1、vue项目中使用proxy来解决
新建一个vite.config.js文件
target: // 代理的接口地址
changeOrigin // 是否允许跨域,默认true
secure // 是否校验https的限制
rewrite // 重写地址,
rewrite: path => path.replace(/^\/dev-api/, '') 重写后,路径上没有dev-api,
rewrite: path => path.replace(/^\/dev-api/, 'dev-api') 注释或者这样写,路径上就有dev-api
proxyReq.setHeader // 是可以动态给他在添加请求头,一般不需要
日志打印的:实际转发目标 就是我们代理应该走的实际路径,在编译器或者cmd上看日志
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
export default defineConfig({
plugins: [uni()],
server: {
proxy: {
'/dev-api': {
target: 'https://cs.he*********',
changeOrigin: true,
secure: false,
rewrite: path => path.replace(/^\/dev-api/, ''), // 可选:重写路径
configure: (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req) => {
proxyReq.setHeader('Host', 'cs.he*******');
proxyReq.setHeader('Origin', 'https://cs.he*******');
proxyReq.setHeader('Referer', 'https://cs.he*******');
console.log('代理请求路径:', req.url, '=>', proxyReq.path) // 检查请求路径
console.log('实际转发目标:',
`${proxyReq.method} ${proxyReq.protocol}//${proxyReq.getHeader('host')}${proxyReq.path}`
)
})
proxy.on('proxyRes', (proxyRes) => {
console.log('实际响应状态码:', proxyRes.statusCode) // 检查响应状态
})
},
}
}
}
})
2、uniapp中全局配置修改
manifest.json中配置
{
"h5": {
"devServer": {
"proxy": {
"/api": {
"target": "http://backend-server:8080",
"changeOrigin": true,
"pathRewrite": { "^/api": "" }
}
}
}
}
}
3、nginx解决方案:
如果没有安装过nginx,来看这个:点我
传统的nginx请求配置
1、nginx.conf文件常规配置
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 9005; //你的服务端口
server_name localhost; //服务名
#下面是与压缩有关的配置,不需要可以不用
gzip on; #开启gzip功能
gzip_min_length 1024; #响应页面数据上限
gzip_buffers 4 16k; #缓存空间大小
gzip_http_version 1.1; #http协议版本
gzip_comp_level 4; #压缩级别4
gzip_types gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php image/jpeg image/gif image/png application/javascript;
gzip_vary on; #启用压缩标识
gzip_static on; #开启文件预压缩
#默认服务,也就是你的localhost:9005 默认展示内容
location / {
root F:/project/xiruan/framework/; #文件名具体地址
index index.html index.htm; #具体文件名
}
#代理,这里就指向另一个地址了
location /dev-api/ {
rewrite ^ https://cs.heb************;
}
}
}
我们这里针对性处理,因为有uniapp需求,所以要加很多东西
proxy_pass 后面是我们的代理地址
add_header 通过这种方法添加请求头
proxy_ssl_verify 是https的校验配置,这里直接关闭
/nginx-1.20.2/logs/api_access.log 这是你的日志放得地方,一个是运行日志,一个是报错日志,直接指向你的盘符地址,比如我这里就是对应的是下面的路径:
location /hx-dev/ {
# 处理 OPTIONS 预检请求,post请求严格
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, X-Request-Id,Authorization, X-Requested-With, X-Token, App-Id'; # 添加 uni-app 特有头
add_header 'Access-Control-Max-Age' 1728000; # 20天缓存
add_header 'Content-Type' 'text/plain; charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
# 解决跨域的核心配置
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, X-Request-Id, Authorization, X-Requested-With, X-Token, App-Id' always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
# 代理配置
proxy_pass https://cs.h**************/; #代理的地址,后面可以拼接 /abc这种,根据你需求来
proxy_set_header Host cs.h*******; #代理的host
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 处理 uni-app 特有头
proxy_set_header X-Token $http_x_token;
proxy_set_header App-Id $http_app_id;
# 日志记录
access_log /nginx-1.20.2/logs/api_access.log;
error_log /nginx-1.20.2/logs/api_error.log;
# HTTPS 相关配置
proxy_ssl_verify off;
proxy_ssl_server_name on;
}
4、node配置请求头方法
app.js中添加跨域请求头
//后端添加请求头解决跨域
app.all('*', function (req, res, next){
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Allow-Credentials", true);
res.header("X-Powered-By", ' 3.2.1');
next();
})