Nginx 跨域 + 无法设置 Cookie 解决办法 + 使用域名访问

首先 F12 看 login 接口对应的网络请求有没有 ⚠️,如果有那是后端的问题,如果没有那是前端的问题

前端问题

前端没有携带 cookie 导致后端识别不到

1) 前端 axios 是否开启了 withCredentials=true

2) 在 OpenAPI 的那边配置项,设置下 withCrendential

img

后端问题

确认环境

1)确保后端跨域注解或者配置要删除,鱼皮项目一般是 config/CrosConfig.java

跨域方式只有一种就可以(一般是后端配置或者 Nginx),咱们这里就使用 Nginx 解决跨域

2)如果使用国内服务器,想要使用域名必须要备案

3)YML 配置

yml
复制代码
server: servlet: session: cookie: domain: 域名或者IP

http 环境就不要使用 secure 和samesite

使用宝塔跨域

Easy 跨域配置

在宝塔前端配置文件

非常重要,一定确保「前端请求地址」和「前端运行地址」地址一致!!! 这种方式需要确保 1、后端没有配置跨域, 一般是 config/CrosConfig.java (具体内容下面的图片) 2、前端请求的地址是,前端运行的 IP 或者前端的域名 比如下面这几种情况 1)比如前端 IP 是 123.123.123.123 那么前端请求后端的地址也是 123.123.123.123 2)比如前端 IP 是 123.123.123.123:90 那么前端请求后端的地址也是 123.123.123.123:90 3)比如前端域名是 leikooo.com 那么前端请求后端请求的地址也是 leikooo.com

image.png

前端请求地址和前端运行地址一致 也就是前端 baseURL 请求 192.168.196.158:8000 具体参考自己运行地址

后端跨域配置

image.png

需要修改宝塔具体位置

image.png image.png

如果是原生的 Nginx 下面是完整的代码,如果是宝塔的话只需要复制两个 location 模块到前端配置文件即可 ,注意一定不要换顺序!

text
复制代码
server { listen 80; server_name 前端 IP 比如 126.4.3.3; root 前端路径; location /api { proxy_pass http://127.0.0.1:后端端口; proxy_set_header Host $proxy_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; proxy_set_header Connection ""; } # 这个要写在下面! location / { index index.html index.htm; try_files $uri $uri/ /index.html; } }

BUG

比如,下面这种情况:

image.png

所以会导致跨域失败!

解决方法:前端的 baseUrl 修改成前端运行地址

Hard 跨域配置

1、如果之前使用的是下面这种跨域方式也要删除掉/注释! image.png

2、这种方式是前端请求一个独立于前端和后端的端口,比如 前端 80 后端 8080 ,那么前端请求 90 端口让 90 对端口进项反向代理到后端

3、上面的 easy 方式虽然简单,但是如果后端想要使用独立的子域名的情况下就不适用了


image-20240914115007224 image-20240914115143570
nginx
复制代码
# 后端相关的反向代理+跨域 server { # 这个监听的端口任意都行,但是要注意前端要请求这个端口 listen 90; server_name 前端 IP 比如 126.4.3.3; location / { # 禁止非 GET|POST|HEAD|OPTIONS|PUT|PATCH|DELET 的请求 if ( $request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|PATCH|DELETE)$ ) { return 444; } set $origin $http_origin; # 重点!比如: # $origin !~ '^http?://leikooo\.com$ # $origin !~ '^http?://127.0.0.1$ if ($origin !~ '^http?://服务器IP$') { set $origin 'http://服务器IP'; } if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "$origin" always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Accept, Authorization' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain charset=UTF-8'; add_header Content-Length 0; return 204; } if ($request_method ~ '(GET|POST|PATCH|PUT|DELETE)') { add_header Access-Control-Allow-Origin "$origin" always; add_header Access-Control-Allow-Methods 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header Access-Control-Allow-Headers 'Content-Type, Accept, Authorization' always; add_header Access-Control-Allow-Credentials true always; } # 反向代理到后端具体运行的端口 proxy_pass http://localhost:后端实际运行端口; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

请求流程图

image.png

使用域名

前端请求后端的域名,然后在 Nginx 配置跨域和反向代理,访问到真正的后端

nginx
复制代码
# 后端相关的反向代理+跨域 server { # http 默认 80 端口 https 默认 443 端口 listen 80; server_name 修改成自己的子域名; # 比如 backend.leikooo.com location / { # 禁止非 GET|POST|HEAD|OPTIONS|PUT|PATCH|DELET 的请求 if ( $request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|PATCH|DELETE)$ ) { return 444; } set $origin $http_origin; # 重点!比如: # $origin !~ '^http?://leikooo\.com$ # 下面配置前端域名,比如 leikooo.cn if ($origin !~ '^http?://前端域名$') { set $origin '前端域名'; } if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "$origin" always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Accept, Authorization' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain charset=UTF-8'; add_header Content-Length 0; return 204; } if ($request_method ~ '(GET|POST|PATCH|PUT|DELETE)') { add_header Access-Control-Allow-Origin "$origin" always; add_header Access-Control-Allow-Methods 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header Access-Control-Allow-Headers 'Content-Type, Accept, Authorization' always; add_header Access-Control-Allow-Credentials true always; } # 反向代理到后端具体运行的端口 # 如果后端开启了 https 不要忘记请求协议变成 https proxy_pass http://localhost:后端实际运行端口; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

注意

1)前端请求 90 (上面 server 模块下 listen 的端口)而不是直接请求后端实际运行端口

image.png

2) 直接请求后端端口,那么 Nginx 就失去了存在的意义!

3)宝塔 + 服务器放行 90 端口,这个要注意!!(具体看自己写的是哪个端口)

4)完成 添加 nginx 配置 + 放行端口 正常就没什么问题了!

5)后端配置文件如果写了 samesite 或者 sercure 属性要删除掉!

image.png

6)后端写了跨域配置要 删除/注释 一般是 @CrossOrigin 或者 CrosConfig

使用原生 Nginx 跨域

经过实际测试,用 nginx 跨域就可以解决

nginx
复制代码
user root; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; access_log logs/access.log; sendfile on; keepalive_timeout 65; #gzip on; # 前端配置不是重点 server { listen 80; server_name 前端 IP 比如 126.4.3.3 ; root /root/app/dist; # 访问默写前端页面 404 就是没加下面这行的原因 try_files $uri $uri/ /index.html; location / { index index.html index.htm; } } # 后端相关的反向代理+跨域 server { # 这个监听的端口任意都行,但是要注意前端要请求这个端口 listen 90; server_name 前端 IP 比如 126.4.3.3; location / { # 禁止非 GET|POST|HEAD|OPTIONS|PUT|PATCH|DELET 的请求 if ( $request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|PATCH|DELETE)$ ) { return 444; } set $origin $http_origin; # 重点!比如: # $origin !~ '^http?://leikooo\.com$ # $origin !~ '^http?://127.0.0.1$ if ($origin !~ '^http?://服务器IP$') { set $origin 'http://服务器IP'; } if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "$origin" always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Accept, Authorization' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain charset=UTF-8'; add_header Content-Length 0; return 204; } if ($request_method ~ '(GET|POST|PATCH|PUT|DELETE)') { add_header Access-Control-Allow-Origin "$origin" always; add_header Access-Control-Allow-Methods 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header Access-Control-Allow-Headers 'Content-Type, Accept, Authorization' always; add_header Access-Control-Allow-Credentials true always; } # 反向代理到后端具体运行的端口 proxy_pass http://localhost:后端实际运行端口; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } }

使用域名

要注意一点,使用了下面的配置,就不需要再更改宝塔前端项目的 Nginx 配置(不需要再添加任何配置,比如 proxy_pass 之类的),当然也不用单独再配置一个前端项目

类似这种

image.png
nginx
复制代码
user root; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; access_log logs/access.log; sendfile on; keepalive_timeout 65; #gzip on; # 前端配置不是重点 server { listen 80; # 修改成前端的域名 server_name leikooo.cn; root /root/app/dist; # 访问默写前端页面 404 就是没加下面这行的原因 try_files $uri $uri/ /index.html; location / { index index.html index.htm; } } # 后端相关的反向代理+跨域 server { # 比如我们配置 backend.leikooo.cn 这个是后端域名 # http 默认 80 端口 https 默认 443 端口 listen 80; server_name 修改成自己的二级域名; # 我设置的一般就是 backend.leikooo.cn location / { # 禁止非 GET|POST|HEAD|OPTIONS|PUT|PATCH|DELET 的请求 if ( $request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|PATCH|DELETE)$ ) { return 444; } set $origin $http_origin; # 重点!比如: # $origin !~ '^http?://leikooo\.com$ # 下面配置前端域名,比如 leikooo、.cn if ($origin !~ '^http?://前端域名$') { set $origin '前端域名'; } if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "$origin" always; add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'Content-Type, Accept, Authorization' always; add_header 'Access-Control-Allow-Credentials' 'true' always; add_header Access-Control-Max-Age 1728000; add_header Content-Type 'text/plain charset=UTF-8'; add_header Content-Length 0; return 204; } if ($request_method ~ '(GET|POST|PATCH|PUT|DELETE)') { add_header Access-Control-Allow-Origin "$origin" always; add_header Access-Control-Allow-Methods 'GET, POST, PATCH, PUT, DELETE, OPTIONS' always; add_header Access-Control-Allow-Headers 'Content-Type, Accept, Authorization' always; add_header Access-Control-Allow-Credentials true always; } # 反向代理到后端具体运行的端口 # 如果后端开启了 https 不要忘记请求协议变成 https proxy_pass http://localhost:后端实际运行端口; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } }

注意

1)前端请求 9090 而不是直接请求后端实际运行端口

2)服务器放行 9090 端口,这个要注意!!(具体看自己写的是哪个端口)

Nginx 解决跨域原理

  1. 跨域问题的原因 跨域问题是由浏览器的 同源策略(Same-Origin Policy) 引起的。同源策略要求: 协议、域名、端口都必须一致。 如果前端和后端运行在不同的域名、IP 或端口上,例如: 前端地址为 http://126.4.3.3 后端地址为 http://126.4.3.3:8080 浏览器会认为它们是不同源,因此会阻止请求,这是跨域问题的本质。
  2. 如何解决跨域问题的配置逻辑 Nginx 配置中,location /api 是关键:
text
复制代码
location /api { proxy_pass http://127.0.0.1:后端端口; proxy_set_header Host $proxy_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; proxy_set_header Connection ""; }

这里通过 Nginx 的反向代理机制: 将前端通过 /api 路径发起的请求转发到后端(即 http://127.0.0.1:后端端口 )。 对于前端来说,请求的域名和端口仍然是 http://126.4.3.3 ,从浏览器的角度看,请求是同源的。

使用 HTTPS

实际测试使用域名 + HTTPS 也可以解决,解决无法设置 cookie 的问题

教程:https://www.codefather.cn/post/1831983737277050881

BUG

1、前端使用域名,但是前端后端使用 ip ,导致 session 设置不上

解决:前后端统一,要用域名都用域名、IP 都用 IP

2、还是不行?

1)检查端口是否放行!!! 2)前端请求的端口是否是 Nginx listen 的端口,不要直接请求实际端口 !!!

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
leikooo
作者分享
ARTS 0815: 分隔链表、大删除是加活不是减负与协议栈如何一层层拆信封
4
DeepSeek Harness 缓存命中率太惊人了,有时候竟然能到 99%,看鱼皮哥的视频竟然还出现过 100% 😱 https://www.bilibili.com/video/BV1VkgK6NEZS
7
ARTS 0809: 反转链表、Shopify 如何用 MySQL 解决超卖与 AI 时代程序员的价值
5
译文:《SwiftUI 七年:平庸的故事》 SwiftUI 在 2019 年高调发布,本应成为苹果全平台成熟、可量产的 UI 未来。七年过去,到了 2026 年,它仍像一场永不结束的 beta:布局难预期、性能不稳、数据流混乱,还几乎没有可靠的向后兼容,开发者被迫写一堆 shim 和 workaround。 作者用苹果官方教程(甚至是有问题的)以及与 UIKit 的对比说明:SwiftUI 用“看起来方便”换掉了精确的工程控制。更深一层,他认为这反映了苹果从 Cocoa、Aqua、Auto Layout 那种不妥协的工艺,转向“够用就行”的企业文化。 SwiftUI 为何存在 苹果并非单纯想提供更好工具,而是不得不应对竞争:React、React Native、Flutter 让“一套代码多端跑”变得诱人;Mac 上原生应用又日渐被网页和 Electron 吃掉。SwiftUI 要同时拴住原生生态、并降低移植到 Mac 的成本。卖点是:响应式数据流、声明式布局、跨平台复用。 数据流 “单一数据源”听起来很美,实际却是 @State、@Binding、ObservedObject,再到 Observation / @Observable 的不断换代。你很难确定视图会更新几次、为何更新;它该忽略的变化会反应,该关心的变化又可能忽略 - - 像个黑盒。 布局系统 基于尺寸协商的布局在 Keynote 里很合理,做浮动视图、自定义侧边栏时却极度不稳定。官方教程里一个很普通的侧边栏,多年仍有问题。布局脆弱到最后往往只能上 GeometryReader - - 一旦用了,声明式优势就没了,还要手算坐标,而且下一版布局规则一变,数学还得重写。 API 稳定与功能对等 代码里满是 if #available。滚动收起键盘要到 iOS 16;工具栏定制很晚才来;网络图片 AsyncImage 要到 iOS 15,缓存相关 API 到 2026 年 7 月仍在 beta。旧 API 常被换掉(如 NavigationView → NavigationStack),开发者要维护多套实现,等于替苹果做 QA。对比 Android 的 Jetpack Compose 可作为依赖打包回退到旧设备,SwiftUI 做不到“写最新 API、稳定回退”。 性能 在真实对比里,即便做了后台解码等优化,SwiftUI 图片网格滚动仍明显不如 UIKit。若展示一堆 JPEG 都得靠顶级芯片撑,架构本身就有问题。 跨平台神话 苹果说的是“学一次、到处用”,不是“写一次、到处跑”。iOS 上学到的布局很少直接适用 Mac;同一套 view 跨平台实现也不一致。结果常变成:学一次、再学一次、某处能用、处处要调。 哲学转向 最大的问题是“够用就行”:覆盖 90% 用例就算成功,用 velocity 掩盖质量下降。作者列举系统与一线应用中的各种瑕疵,认为这不是偶然,而是苹果主动降低质量门槛 - - 所以即使过了七年,他仍不信任 SwiftUI。 结论 对构建稳定、高性能、可维护系统真正重要的部分,SwiftUI 几乎都有问题。它不是“极差”,而是平庸 - - 用假便利换真精度,要么你花时间给框架打补丁,要么把半成品发出去。作者更宁愿继续用“遗留”的 UIKit / AppKit。 最后小总结: 最让人不能接受的不是“SwiftUI 还有 bug”,而是它把“看起来很快”当成了工程上的完成态。声明式、预览、跨平台,每一项都在秀高级感,可真正写进业务后,你面对的是难预测的重绘、脆弱的布局、层层 #available,以及把兼容和排错外包给业务方的现实。七年够长了,若还靠“框架还年轻”解释,那更像是对标准的侮辱。技术选型从来不只是语法偏好,而是你选的是可预期性、可维护成本,以及对用户体验的态度。平庸的“成功”往往比明显失败更危险 ,你说它能上线、能 demo、能交差,但是却在细节里一点点磨损信任。工具可以换代,但对质量的要求不该跟着一起降级。
4
ARTS 0802: 合并有序链表、AI 时代的技术断层与 TCP 200ms 延迟之谜
5
下载 APP