拓冰建站拓冰建站
首页 / 资讯中心 / 正文

05-跨域问题彻底解决:SaaS后台、小程序、工控端跨域统一配置

05-跨域问题彻底解决SaaS后台、小程序、工控端跨域统一配置哈喽我是黒漂技术佬。有没有过这种经历——前端跑在 localhost:8080后端跑在 localhost:8081结果浏览器甩你一脸红字“has been blocked by CORS policy”然后你在网上搜了一堆方案什么CrossOrigin、什么add_header改来改去要么不生效要么开发环境好了生产环境又崩了。今天这篇咱们把跨域这件事从头到尾说清楚并且针对无人售货柜的三端场景SaaS后台、小程序、工控屏给出一个统一的 Nginx 跨域配置方案。一、跨域是怎么来的——同源策略的前世今生跨域的本质是浏览器的同源策略在起作用。所谓同源指的是协议 域名 端口三者完全相同。比如http://localhost:8080和http://localhost:8081端口不同那就是跨域。同源策略不是服务器端的安全机制而是浏览器强制执行的安全规则。换句话说跨域请求其实已经发出去了服务器也正常响应了只是浏览器收到响应后发现 “哦这个响应的源和当前页面的源不一样”然后就把它拦截了——你在 Network 面板能看到 200 状态码但控制台报跨域错误就是这个原因。这个机制本身是为了防止 CSRF 攻击假如你已经登录了银行网站浏览器里有一个银行 Cookie这时候你不小心点开了恶意网站恶意网站偷偷向银行接口发 AJAX 请求——如果没有同源策略它就能拿着你的 Cookie 操作你的账户。而同源策略要求请求必须来自同一个源这就把大部分 CSRF 挡在了门外。二、CORS 原理详解——OPTIONS 预检请求是怎么回事要解决跨域就得用CORSCross-Origin Resource Sharing跨域资源共享这套标准协议。CORS 把请求分成两类1简单请求同时满足以下三个条件的就是简单请求方法只能是 GET、HEAD、POST只能使用Accept、Accept-Language、Content-Language、Content-Type且值只能是text/plain、multipart/form-data、application/x-www-form-urlencoded这几个首部不能使用ReadableStream简单请求浏览器直接发出然后在响应头里检查Access-Control-Allow-Origin。有就放行没有就报错。流程简单直接。2非简单请求——OPTIONS 预检只要不满足上述任何一个条件就是非简单请求。比如你用了Content-Type: application/json或者加了自定义 Header 如Authorization令牌浏览器不会直接发你的请求而是先发一个 OPTIONS 方法的预检请求去问服务器“嘿我接下来要发一个 PUT 请求还带了 Authorization 头你同不同意”服务器如果同意就在 OPTIONS 响应中返回这些关键字段Access-Control-Allow-Origin: https://admin.smartkaba.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization, X-Device-Token Access-Control-Max-Age: 86400浏览器收到这些头核对自己的请求是否在允许范围内通过了才会发出真正的请求。Access-Control-Max-Age是这个预检结果的缓存时间秒设 86400 就是一天省得每次请求都预检——这对工控屏这种低性能设备来说尤其重要。还有一个容易被忽略的头Access-Control-Allow-Credentials。如果你需要前端携带 Cookie 或 HTTP 认证信息这个头必须设为true而且此时Access-Control-Allow-Origin不能是星号*——必须是具体的域名。这是 CORS 规范里的硬性约束。三、Nginx 解决跨域三种方案方案一add_header 添加响应头最直接在 Nginx 的 location 块里直接加上 CORS 头location /api/ { # 处理预检请求 if ($request_method OPTIONS) { add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Methods GET, POST, PUT, DELETE, PATCH, OPTIONS; add_header Access-Control-Allow-Headers Content-Type, Authorization, X-Device-Token, X-Requested-With; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Max-Age 86400; return 204; } # 正常请求也加上 add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Credentials true always; proxy_pass http://backend_cluster; }注意always参数——不加它当后端返回 4xx/5xx 时 add_header 不会生效导致浏览器收不到 CORS 头而报错。用$http_origin动态反射请求来源域名比写死星号更灵活也更安全。优点配置集中逻辑清晰不改后端代码。缺点如果多层 Nginx 或者又配了 add_header后面会覆盖前面——因为 Nginx 的 add_header 指令在继承上有特殊规则。方案二反向代理同源最彻底既然跨域是因为源不同那把前后端放到同一个源不就完了server { listen 80; server_name admin.smartkaba.com; # 前端静态资源 location / { root /var/www/admin-web/dist; try_files $uri $uri/ /index.html; } # 后端 API 反代到同一个域名下 location /api/ { proxy_pass http://gateway:8080/api/; } }前端访问admin.smartkaba.com/api/user/list浏览器认为这是同源请求压根不会触发 CORS 检查。这实际上是最彻底的跨域解决方案——因为根本没有跨域。优点根本上消灭跨域问题不需要处理 OPTIONS 预检。缺点要求前后端部署在同一域名下如果前端和后端分属不同团队、不同域名这个方案就不适用。方案三JSONP过时方案仅作了解利用script标签不受同源策略限制的特性动态创建 script 元素来获取数据。JSONP 只支持 GET 请求安全性差要信任第三方返回的 JS 代码执行在 2025 年的今天完全没必要用此处仅作提及。四、无人售货柜三端跨域场景与统一配置咱们的无人售货柜系统有三端端场景跨域需求SaaS 管理后台Web运营人员在浏览器中管理商品、订单、设备浏览器环境受同源策略限制微信小程序用户扫码开门、选购支付小程序内置浏览器域名需在微信后台配置工控屏Android/嵌入式售货柜机身大屏实时展示商品WebView 环境一样受同源策略限制统一配置方案既然三端都要访问后端 API我们选择方案一 方案二组合SaaS 后台和工控屏走反向代理同源前后端部署在同一域名下彻底避免跨域。小程序域名天然不同且微信要求配置合法域名走CORS add_header方案。完整 Nginx 配置# SaaS管理后台 - 同源部署不跨域 server { listen 80; server_name admin.smartkaba.com; location / { root /var/www/admin-web/dist; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://gateway:8080/api/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } # 小程序专用 - 跨域配置 server { listen 80; server_name api.smartkaba.com; set $cors_origin ; if ($http_origin ~* ^https://(.*\.)?smartkaba\.com$) { set $cors_origin $http_origin; } location /api/ { if ($request_method OPTIONS) { add_header Access-Control-Allow-Origin $cors_origin; add_header Access-Control-Allow-Methods GET, POST, PUT, DELETE, PATCH, OPTIONS; add_header Access-Control-Allow-Headers Content-Type, Authorization, X-Device-Token; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Max-Age 86400; return 204; } add_header Access-Control-Allow-Origin $cors_origin always; add_header Access-Control-Allow-Credentials true always; proxy_pass http://gateway:8080/api/; } } # 工控屏 - 同源部署 server { listen 80; server_name device.smartkaba.com; location / { root /var/www/device-web/dist; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://gateway:8080/api/; } }亮点解析小程序那个$cors_origin变量用正则匹配了smartkaba.com及其子域名而不是无脑设星号——这样既安全只放行自家域名又灵活开发环境和生产环境都能用。五、常见跨域报错与排查清单报错1Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header原因OPTIONS 预检请求没拿到 CORS 头。常见情况是 Nginx 里只写了add_header但 OPTIONS 请求被透传给了后端而后端没处理。解决在 Nginx 里直接拦截 OPTIONS 返回 204。报错2The value of the Access-Control-Allow-Origin header must not be the wildcard * when the requests credentials mode is include原因前端设置了withCredentials: trueAxios 默认 false但后端返回了Access-Control-Allow-Origin: *。解决改用$http_origin反射具体域名。报错3生产环境跨域正常开发环境报错原因生产环境用了反向代理同源开发环境是 localhost:5173 直连后端。解决开发环境用 Vite/Webpack 的 proxy 功能做转发或者给后端开发环境加上 CORS 配置。报错4后端接口加了CrossOrigin注解Nginx 也配了add_header还是不生效原因两个地方都在加头但 Nginx 的响应头被后端的覆盖了或反过来或者 Cookie 的 SameSite 属性导致请求没带凭证。排查打开浏览器 DevTools → Network看响应头到底有没有、值对不对。排查口诀先看 Network 有没有响应 → 再看有没有 OPTIONS 预检 → 再看响应头里有没有 CORS 头 → 最后看值是否正确。按这个顺序90% 的跨域问题都能定位。总结跨域不是 bug是浏览器为了保护你而设的安全机制。理解了同源策略和 CORS 预检流程之后解决起来无非三招反向代理同源一劳永逸、add_header 精准放行、JSONP 直接遗忘。在无人售货柜这种多端场景下后台和工控屏走同源部署小程序走 CORS 配置是最干净最可维护的方案。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门