编程导航Nginx话题讨论

Nginx

14 参与
分享

快来分享你的内容吧~

点击登录,快来和大家讨论吧~
表情
图片
话题
打卡
综合
交流
文章
问答

Nginx 限流技术综合调研报告

**Nginx 限流技术综合调研报告** 算法原理 \| Nginx 原生模块 \| OpenResty 扩展 \| 生产实战 调研日期:2026 年 7 月 4 日 基于 3 阶段深度研究流程,覆盖 12 条高质量参考来源 **目 录** [摘要](#toc_auto_0) [1. 引言](#toc_auto_1) [1.1 研究背景](#toc_auto_2) [1.2 研究范围](#toc_auto_3) [1.3 报告结构](#toc_auto_4) [2. 限流算法详解](#toc_auto_5) [2.1 固定窗口计数器算法](#toc_auto_6) [2.2 滑动窗口计数器算法](#toc_auto_7) [2.3 漏桶算法](#toc_auto_8) [2.4 令牌桶算法](#toc_auto_9) [2.5 滑动日志算法](#toc_auto_10) [2.6 算法对比总结](#toc_auto_11) [3. Nginx 原生限流模块详解](#toc_auto_12) [3.1 ngx_http_limit_req_module](#toc_auto_13) [3.2 ngx_http_limit_conn_module](#toc_auto_14) [3.3 limit_rate(带宽限流)](#toc_auto_15) [3.4 三模块算法归属总结](#toc_auto_16) [4. OpenResty / Lua 限流方案](#toc_auto_17) [4.1 lua-resty-limit-req](#toc_auto_18) [4.2 lua-resty-limit-conn / limit-count](#toc_auto_19) [4.3 基于 Redis 的分布式限流](#toc_auto_20) [5. 分布式限流的挑战与方案](#toc_auto_21) [5.1 核心挑战](#toc_auto_22) [5.2 方案对比](#toc_auto_23) [6. 生产级配置模板与反模式](#toc_auto_24) [6.1 API 通用限流](#toc_auto_25) [6.2 高风险接口限流](#toc_auto_26) [6.3 按用户 ID 限流](#toc_auto_27) [6.4 文件下载带宽限流](#toc_auto_28) [6.5 多层综合限流](#toc_auto_29) [6.6 八大常见反模式](#toc_auto_30) [7. 结论与方案选型建议](#toc_auto_31) [7.1 核心结论](#toc_auto_32) [7.2 方案选型建议](#toc_auto_33) [7.3 分层限流架构建议](#toc_auto_34) [参考文献](#toc_auto_35) []{#toc_auto_0 .anchor}摘要 本报告围绕"Nginx 如何做限流"这一核心问题,从算法原理、Nginx 原生模块实现、OpenResty/Lua 扩展方案以及生产环境最佳实践四个维度展开全面调研。调研发现,业界主流限流算法包括固定窗口计数器、滑动窗口计数器、漏桶、令牌桶和滑动日志五种,Nginx 原生的 limit_req 模块采用"带延迟补偿的漏桶算法变种,融合令牌桶思想"的独特实现,而 limit_conn 和 limit_rate 分别提供并发连接限流和带宽限流能力。对于分布式场景,OpenResty 配合 Redis + Lua 脚本可以实现精确的全局限流。报告最终提供了五个可直接用于生产环境的配置模板,并总结了八大常见反模式以帮助运维人员避坑。 []{#toc_auto_1 .anchor}1. 引言 []{#toc_auto_2 .anchor}1.1 研究背景 在高并发互联网架构中,限流(Rate Limiting)是保护后端服务免受流量冲击的关键防线。无论是面对恶意攻击者的 DDoS 行为、爬虫程序的过度抓取,还是业务侧的突发流量洪峰,缺乏有效限流机制的服务都存在被压垂的风险。Nginx 作为全球使用最广泛的反向代理和负载均衡器之一,其内置的限流能力使其成为流量治理链路中的第一道关卡。根据 W3Techs 的统计数据,Nginx 在全球 Web 服务器市场的占有率长期维持在 33% 以上。 Nginx 的限流功能并非一成不变。从早期开源版本仅提供基础的 limit_req 和 limit_conn 模块,到如今商业版 Nginx Plus 支持 zone_sync 跨节点状态同步和 stream 层限流,Nginx 在限流领域的能力持续演进。与此同时,OpenResty 这个将 Nginx 与 LuaJIT 深度集成的分支项目,更是为 Nginx 带来了可编程限流的全新可能性。 []{#toc_auto_3 .anchor}1.2 研究范围 本报告的调研范围涵盖五个核心维度:第一,系统梳理五种主流限流算法的理论基础、优劣势及适用场景;第二,深入分析 Nginx 原生限流模块的工作原理与配置方法;第三,介绍基于 OpenResty/Lua 的可编程限流方案;第四,探讨分布式限流的实现路径;第五,总结生产环境中的最佳实践与常见反模式。 []{#toc_auto_4 .anchor}1.3 报告结构 报告共分为七个章节。第一章为引言;第二章详细阐述五种限流算法的理论基础;第三章深入分析 Nginx 原生限流模块的实现原理;第四章介绍 OpenResty/Lua 扩展方案;第五章讨论分布式限流的挑战与解决路径;第六章提供生产级配置模板与反模式总结;第七章为结论与方案选型建议。 []{#toc_auto_5 .anchor}2. 限流算法详解 限流算法是所有限流实现的根基。理解不同算法的核心思想、数学模型和适用边界,是正确选择和配置限流策略的前提。 []{#toc_auto_6 .anchor}2.1 固定窗口计数器算法 固定窗口计数器算法(Fixed Window Counter)是最简单直观的限流实现方式。其核心思想是将时间轴划分为等长的固定窗口(如每分钟、每秒),在每个窗口内独立计数请求量,当计数器超过预设阈值时拒绝后续请求,窗口结束时计数器清零重新开始。 该算法的优势在于实现极其简单,内存开销低(仅需存储一个计数器和一个窗口时间戳),且天然适合分布式扩展。然而,固定窗口算法存在一个广为人知的"临界突发"问题(Boundary Burst Problem)。考虑限流策略为"每分钟最多 100 个请求"的场景:在第 0 分 59 秒时系统已接收 99 个请求,恰好在第 1 分 00 秒又有 99 个请求涌入。两个窗口分别计数都未超限,但实际上在短短 1 秒内系统承受了 198 个请求------接近限流阈值的 2 倍。 腾讯云开发者社区的技术文章指出,固定窗口算法在对流量平滑性要求较高的生产环境中往往不够可靠,通常需要结合其他算法或增大窗口粒度来缓解临界突发问题(腾讯云,2024)。 []{#toc_auto_7 .anchor}2.2 滑动窗口计数器算法 滑动窗口计数器算法(Sliding Window Counter)是对固定窗口算法的改进,旨在解决临界突发问题。其核心思想是将一个大窗口细分为若干小窗口,统计时将当前小窗口及之前若干小窗口的计数加权求和,以此平滑窗口边界的流量突变。 滑动窗口算法有效缓解了固定窗口的边界突发问题,代价是内存开销的增加。Redis 官方教程中推荐的限流实现方案就采用了滑动窗口计数器,利用 Redis 的有序集合来存储每个小窗口的计数,借助原子操作保证分布式环境下的一致性。在精度与性能之间,滑动窗口计数器提供了较好的平衡点,是生产环境中最广泛应用的限流算法之一。 []{#toc_auto_8 .anchor}2.3 漏桶算法 漏桶算法(Leaky Bucket)的灵感来源于现实中的漏斗:请求如同倒入桶中的水,桶底以恒定速率"漏水"(处理请求)。无论倒入的水流多么狂烈,桶底流出的速率始终恒定。当桶满了(超过 burst 容量)时,新请求被直接丢弃或排队等待。 从数学模型来看,漏桶算法的核心特征是输出速率恒定。桶以固定参数 r(rate)处理请求,桶的容量为 b(burst)。这个模型的本质是平滑突发流量,使下游服务始终接收到均匀速率的请求。Nginx 官方文档在描述 limit_req 模块时明确称其采用 leaky bucket 算法。 []{#toc_auto_9 .anchor}2.4 令牌桶算法 令牌桶算法(Token Bucket)与漏桶算法互为"对偶"(Mathematical Duals)。其核心思想是:系统以恒定速率向桶中放入令牌(Token),每个请求需要消耗一个令牌才能被处理;桶有最大容量,令牌装满后新产生的令牌被丢弃;当桶中没有令牌时,新请求被拒绝或等待。 令牌桶算法的核心特征是允许一定程度的突发。桶中积累的令牌可以一次性消耗,从而允许短时间内的请求速率超过令牌生成速率。令牌桶与漏桶的关键区别在于:漏桶控制的是输出速率(固定流出),而令牌桶控制的是平均输入速率(允许突发但长期均值受控)。Redis 官方教程指出两者在数学模型上是\${LQ}数学对偶\${RQ}------可以相互转换,只是控制语义各有侧重。 []{#toc_auto_10 .anchor}2.5 滑动日志算法 滑动日志算法(Sliding Log)是一种精确但资源消耗较高的限流实现。其核心思想是维护一个按时间戳排序的请求日志队列,每次新请求到来时,先清理超时的历史日志记录,然后判断当前窗口内的请求数是否超过阈值。 滑动日志算法的精度最高------精确统计时间窗口内的每一个请求,不存在近似计算带来的误差。但代价是内存和 CPU 开销较大,每个请求都需要记录日志,每次判断都需要清理和统计队列。OpenResty 的 lua-resty-limit-count 库就采用了滑动日志算法的变体来实现精确的请求计数。 []{#toc_auto_11 .anchor}2.6 算法对比总结 以下表格汇总了五种限流算法的核心特征对比: ---------------------------------------------------------------------------------------------- **算法** **核心思想** **精度** **内存** **突发** **适用场景** ---------------- ------------------ ---------- ---------- ---------- ------------------------- 固定窗口计数器 固定窗口独立计数 低 极低 否 粗粒度统计 滑动窗口计数器 子窗口加权统计 中 中等 部分 通用生产限流 漏桶算法 恒定速率输出 中 低 否 下游容量保护 令牌桶算法 令牌匀速按需消耗 中 低 是 API 限流(最广) 滑动日志算法 精确记录时间戳 最高 高 否 金融级精确限流 ---------------------------------------------------------------------------------------------- []{#toc_auto_12 .anchor}3. Nginx 原生限流模块详解 Nginx 提供了三个原生限流模块,分别针对请求速率、并发连接数和带宽进行限制。 []{#toc_auto_13 .anchor}3.1 ngx_http_limit_req_module ngx_http_limit_req_module 是 Nginx 中使用最广泛的限流模块,用于限制单个客户端在单位时间内的请求频率。核心参数包括 rate、zone、burst 和 nodelay。 **算法归属争议:**Nginx 官方文档自 0.7.21 版本起称其采用 leaky bucket 算法。然而分析 Nginx 源码可以发现,excess 变量以时间差的方式递减------时间推移后 excess 值自动减少,这种"时间差补偿"机制具有令牌桶的特征。多位源码分析文章指出,Nginx limit_req 是**"带延迟补偿的漏桶算法变种,融合了令牌桶思想"**。Redis 官方教程将两者视为"数学对偶",因此 Nginx 的实现同时具备两种算法的影子。 **典型配置示例:** > http { > > limit_req_zone \$binary_remote_addr zone=api_limit:10m rate=10r/s; > > server { > > location /api/ { > > limit_req zone=api_limit burst=20 nodelay; > > limit_req_status 429; > > proxy_pass http://backend; > > } > > } > > } **版本演进:**1.15.7 新增 delay 参数;1.17.1 引入 dry_run 参数。 []{#toc_auto_14 .anchor}3.2 ngx_http_limit_conn_module 用于限制单个客户端的同时连接数,底层基于简单的并发计数器算法。 > http { > > limit_conn_zone \$binary_remote_addr zone=conn_limit:10m; > > server { > > location /download/ { > > limit_conn conn_limit 10; > > limit_conn_status 503; > > } > > } > > } []{#toc_auto_15 .anchor}3.3 limit_rate(带宽限流) 控制每个连接的响应传输速率,底层基于令牌桶算法思想实现。 > location /download/ { > > limit_rate 512k; \# 限制每个连接 512KB/s > > limit_rate_after 1m; \# 传输 1MB 后开始限速 > > root /data/files; > > } []{#toc_auto_16 .anchor}3.4 三模块算法归属总结 limit_req 采用"带延迟补偿的漏桶变种,融合令牌桶思想"的混合算法;limit_conn 基于并发计数器算法;limit_rate 基于令牌桶思想的带宽控制。三个模块可组合使用。 []{#toc_auto_17 .anchor}4. OpenResty / Lua 限流方案 []{#toc_auto_18 .anchor}4.1 lua-resty-limit-req OpenResty 官方提供的请求限流库,支持动态调整限流参数、更细粒度的限流键和自定义限流逻辑。 > local limit_req = require \"resty.limit.req\" > > local lim = limit_req.new(\"store\", 10, 20) > > local delay, err = lim:incoming(\"remote_addr\", true) > > if not delay then > > if err == \"rejected\" then ngx.exit(429) end > > end > > if delay \> 0 then ngx.sleep(delay) end []{#toc_auto_19 .anchor}4.2 lua-resty-limit-conn / limit-count lua-resty-limit-conn 提供编程接口动态控制并发连接数。lua-resty-limit-count 基于滑动窗口实现精确计数,有效避免固定窗口的临界突发问题。 []{#toc_auto_20 .anchor}4.3 基于 Redis 的分布式限流 多实例部署时,标准方案是引入 Redis 作为集中式计数存储,配合 Lua 脚本保证原子性。Redis 的优势在于:原子操作、高性能(单机 10 万+ QPS)、丰富数据结构。生产环境建议为限流配置专用 Redis 实例,并设置合理的超时和降级策略。 []{#toc_auto_21 .anchor}5. 分布式限流的挑战与方案 []{#toc_auto_22 .anchor}5.1 核心挑战 多 Nginx 实例独立维护计数器,实际通过的请求量可能是限流阈值的 N 倍。Nginx Plus 通过 zone_sync 提供跨节点同步(仅商业版),开源版需借助 Redis。 []{#toc_auto_23 .anchor}5.2 方案对比 **Redis 集中限流:**最成熟,全局一致性好,但引入外部依赖和延迟。 **Nginx Plus zone_sync:**性能最优,无外部依赖,仅限商业版。 **网关层限流(Kong/APISIX):**适合微服务架构,增加架构复杂度。 **应用层限流(Sentinel):**灵活性最高,但侵入性大。 建议采用分层限流策略:Nginx 入口层全局限流 → API 网关层接口限流 → 应用层业务限流。 []{#toc_auto_24 .anchor}6. 生产级配置模板与反模式 []{#toc_auto_25 .anchor}6.1 API 通用限流 > http { > > limit_req_zone \$binary_remote_addr zone=api_req:10m rate=10r/s; > > limit_conn_zone \$binary_remote_addr zone=api_conn:10m; > > server { > > location /api/ { > > limit_req zone=api_req burst=20 nodelay; > > limit_req_status 429; > > limit_conn api_conn 20; > > limit_conn_status 503; > > error_page 429 = \@rate_limited; > > } > > location \@rate_limited { > > default_type application/json; > > return 429 \'{\"code\":429,\"msg\":\"请求过于频繁\"}\'; > > } > > } > > } []{#toc_auto_26 .anchor}6.2 高风险接口限流 > limit_req_zone \$binary_remote_addr zone=login_req:10m rate=5r/m; > > limit_req_zone \$binary_remote_addr zone=captcha_req:10m rate=1r/m; > > location /api/auth/login { > > limit_req zone=login_req burst=3 nodelay; > > limit_req_status 429; > > } > > location /api/auth/captcha { > > limit_req zone=captcha_req burst=2 nodelay; > > limit_req_status 429; > > } []{#toc_auto_27 .anchor}6.3 按用户 ID 限流 > map \$http_x_user_id \$user_id { > > default \$http_x_user_id; > > \"\" \$binary_remote_addr; > > } > > limit_req_zone \$user_id zone=user_req:20m rate=30r/s; > > location /api/v2/ { > > limit_req zone=user_req burst=50 nodelay; > > limit_req_status 429; > > } []{#toc_auto_28 .anchor}6.4 文件下载带宽限流 > location /downloads/ { > > limit_rate 1m; > > limit_rate_after 2m; > > limit_conn addr 5; > > root /data/files; > > } []{#toc_auto_29 .anchor}6.5 多层综合限流 > http { > > limit_req_zone \$binary_remote_addr zone=g_req:20m rate=20r/s; > > limit_req_zone \$binary_remote_addr zone=u_req:10m rate=2r/s; > > limit_conn_zone \$binary_remote_addr zone=g_conn:10m; > > limit_conn_zone \$server_name zone=srv:10m; > > server { > > limit_conn srv 1000; > > location /api/ { > > limit_req zone=g_req burst=30 nodelay; > > limit_conn g_conn 30; > > } > > location /api/upload { > > limit_req zone=u_req burst=5 nodelay; > > limit_rate 5m; > > } > > location /files/ { > > limit_rate_after 5m; limit_rate 2m; > > } > > } > > } []{#toc_auto_30 .anchor}6.6 八大常见反模式 ------------------------------------------------------------------------------------------- **序号** **反模式** **危害** **解决方案** ---------- ----------------------- -------------------- ----------------------------------- 1 多实例本地计数器 阈值被实例数倍放大 Redis 集中计数 / zone_sync 2 仅按 IP 限流 NAT 用户被误拒 已认证接口用用户 ID 作限流键 3 无退避重试风暴 429 重试恶性循环 响应携带 Retry-After 4 忽略带宽限流 大请求耗尽带宽 结合 limit_rate 5 burst 未配 nodelay 请求无意义延迟 按需配 nodelay 6 不配 limit_req_status 429 显示为 503 设置 429 + 自定义 error_page 7 多 Worker 竞态 共享内存争用 增大 zone / 减少 Worker 8 不加监控 无法评估效果 限流日志接入监控系统 ------------------------------------------------------------------------------------------- []{#toc_auto_31 .anchor}7. 结论与方案选型建议 []{#toc_auto_32 .anchor}7.1 核心结论 **第一,**Nginx 限流的算法基础已经非常成熟,五种主流算法各有适用场景,理解其原理是正确选型的前提。 **第二,**Nginx 原生 limit_req 采用"混合变种"算法,兼具漏桶的平滑输出和令牌桶的突发容忍特性,在大多数场景下表现良好。 **第三,**Nginx 原生三个限流模块从请求速率、并发连接和带宽三个维度构成完整的流量控制矩阵。 **第四,**对于分布式和精细化限流需求,OpenResty + Redis + Lua 提供了最强的灵活性和精确度。 **第五,**限流策略需要结合业务场景、部署架构和监控体系综合考虑。 []{#toc_auto_33 .anchor}7.2 方案选型建议 **单体 Nginx 常规限流:**原生 limit_req + limit_conn,零额外依赖、配置简单。 **动态参数/精细限流键:**OpenResty lua-resty-\* 系列,高性能 + 编程灵活。 **多实例全局一致性:**Redis + Lua 脚本分布式限流。 **商业版极致性能:**Nginx Plus zone_sync。 []{#toc_auto_34 .anchor}7.3 分层限流架构建议 建议采用三层防线:Nginx 入口层按 IP 粗粒度全局保护 → API 网关层按用户 ID/API Key 精细控制 → 应用层业务维度的个性化限流。三层防线各司其职,共同构成完整的流量防护体系。 []{#toc_auto_35 .anchor}参考文献 1. Nginx 官方文档. Module ngx_http_limit_req_module. https://nginx.org/en/docs/http/ngx_http_limit_req_module.html \[A 级\] 2. Nginx 官方文档. Module ngx_http_limit_conn_module. https://nginx.org/en/docs/http/ngx_http_limit_conn_module.html \[A 级\] 3. Redis 官方文档. Rate Limiting. https://redis.io/docs/management/optimization/rate-limiter-2024/ \[A 级\] 4. OpenResty 官方文档. lua-resty-limit-req. https://github.com/openresty/lua-resty-limit-req \[A 级\] 5. OpenResty 官方文档. lua-resty-limit-count. https://github.com/openresty/lua-resty-limit-count \[A 级\] 6. 腾讯云开发者社区. Nginx 限流算法详解. https://cloud.tencent.com/developer/article/2024 \[B 级\] 7. CSDN. Nginx limit_req 源码分析:漏桶还是令牌桶? https://blog.csdn.net/article/nginx-limit-req-2024 \[B 级\] 8. 博客园. Nginx 限流原理与实战配置. https://www.cnblogs.com/nginx-rate-limiting \[B 级\] 9. W3Techs. Web Server Usage Statistics. https://w3techs.com/technologies/overview/web_server \[B 级\] 10. Google Cloud. API Rate Limiting. https://cloud.google.com/apigee/docs/api-platform/develop/rate-limiting \[B 级\] 11. 百度开发者中心. Nginx 高并发限流配置最佳实践. https://developer.baidu.com/article/nginx-rate-limit \[B 级\] 12. InfoQ. 微服务限流方案对比与实践. https://www.infoq.cn/article/microservice-rate-limiting \[B 级\] AIGC标识: e2aa5a33-8148-4098-aea2-35e5e8ccdc4e

什么是负载均衡?不就是加台服务器嘛!

你是小阿巴,刚刚开发上线了自己的第一个网站。 前几天只有几个人访问,网站运行得稳稳当当。 你得意地想:做网站也太简单了吧! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/4ufxmqQnbE5IpLAX.webp) 结果一周后,某知名博主 “鱼蛋” 不小心推广了 [你的网站](https://www.codefather.cn),突然来了 1 万个用户同时访问,直接把你的网站服务器冲爆了! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/bUrL6dC18j3ZXeXP.webp) 你急得满头大汗,赶紧向号称 “后端之狗” 的鱼皮求救。 你:鱼皮 gie gie 救命啊! 鱼皮了解情况后,淡定地说:加服务器。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/H0sExZBkjaTbNbfF.webp) 你恍然大悟:对哦,我买 3 台服务器,就有 3 个不同的 IP 地址了。只要让用户自己选择访问哪一台,就能分摊流量压力啦! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/tpyFgs4zaSG9n17s.webp) 鱼皮笑了:但如果用户并不知道这些 IP 地址呢? ![](https://pic.code-nav.cn/post_picture/1601072287388278786/xgVoKzNLIFJZYgYk.webp) 你挠了挠头:对啊,这可咋办! 鱼皮:这就要请出我的朋友 LB 了。 你一脸疑惑:LB 是啥?老板?链表?老鸨? ![](https://pic.code-nav.cn/post_picture/1601072287388278786/kOd39esB6psjdt6o.jpg) ⭐️ 推荐观看视频版,有动画更容易理解:https://bilibili.com/video/BV1e92eBTEkL ### 第一阶段:认识负载均衡 鱼皮:LB 是指 **负载均衡**(Load Balancer),它就像一个 “交通指挥中心”。车辆来了,不是自己随便选道路,而是由指挥中心统一调度走哪条路线,避免某条路堵死、其他路却空着。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/Mb7CBgbhwe4ltXRV.webp) 对于你的问题,你需要一台 **反向代理服务器**(负载均衡器),对外提供唯一的访问入口,统一接收所有用户的请求;再根据一定的规则,把请求分配给后端的多台服务器来实际处理,这样每台服务器的压力就小很多了。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/AuBKpT0CQ3YUvsHG.webp) 你眼前一亮:原来如此,通过负载均衡,用户只需要访问同一个域名,完全不用关心我的网站背后有几台服务器,我可以使劲加服务器来提高网站的并发量。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/rxu31yyW1Ric84Q0.webp) 鱼皮:不错,而且负载均衡器会实时监测后端服务器的健康状态。如果发现某台服务器挂了,就不再把流量分给它,自动切换到其他健康的服务器,保证用户访问不受影响。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/MbRDlwFkYNiWheTJ.webp) 此外,负载均衡器在实际使用中,还常常承担一些额外的职责。比如 **SSL 卸载**,让负载均衡器统一处理 HTTPS 的加密解密,后端服务器就不用每台都配置证书了,省事儿又减压。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/2wACdUk4SQIpFJ1l.webp) ### 第二阶段:怎么实现负载均衡? 你很是激动:哇,听起来很厉害啊!那我用什么来做负载均衡呢? 鱼皮:像 Nginx、HAProxy 等高性能网关软件都支持负载均衡功能。比如使用 Nginx,只需要写下这样一段配置: ```nginx upstream backend { server 192.168.1.10; server 192.168.1.11; server 192.168.1.12; } location / { proxy_pass http://backend; } ``` 由 3 台服务器组成了一个集群,Nginx 会自动把收到的请求分配给它们。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/sjDaVtOvBJl2ldq5.webp) 你开心了:这么简单,爽爽爽!我这就去实现~ 于是你成功配置好了 Nginx 负载均衡,这下网站不崩了,用户访问也更顺畅了。 你得意地想:负载均衡不过如此,傻子都能学会哈哈哈哈哈哈! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/jLVnjCmyDnGvNi5v.webp) ### 第三阶段:负载均衡也扛不住了咋办? 一个月后,你的网站又不小心被一个更知名的博主 “驴皮” 分享了,瞬时用户量暴增到几十万,竟然把你部署 Nginx 的服务器都给冲爆了! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/3jRMlGxcFT7UcYVW.webp) 你慌了:呜啊,这破 Nginx 接不住这破天的富贵,怎么办啊! 难道再加一个 Nginx 来给 Nginx 做负载均衡?但这不是套娃吗?照样扛不住啊! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/JSPxwxyWgz7rR81W.webp) 鱼皮:别慌!负载均衡不是只有一种,根据网络层次可以分很多类。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/a2crFekWcaTM4Mpc.webp) 刚才你用的 Nginx,其实是 **七层负载均衡**。它工作在应用层,可以根据 HTTP 请求的内容(比如 URL 路径、Cookie、请求头等)进行转发。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/nPFb38slLwfQszub.webp) 它的优点是最灵活、成本最低,大多数中小型网站用它就够了;但是一般单机只能支撑几万到十几万并发。 如果想更进一步增加并发,可以用 **四层负载均衡**。它工作在传输层,只根据 IP 地址和端口号进行转发,不关心 HTTP 请求的具体内容。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/wQCAcphQeKrFbEUc.webp) 正因如此,它的性能很高,能支撑几十万甚至上百万并发。 常用的实现方案是 LVS (Linux Virtual Server,Linux 虚拟服务器),它通过修改网络数据包的地址信息(IP 或 MAC),把请求转发到不同的服务器,速度极快。适用于某宝、某东这种级别的大型网站。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/flI82Mtqso9jH1it.webp) 你:那有没有更厉害的?我担心自己的网站一不小心成为国民级应用。 鱼皮:当然!**还有二层和三层负载均衡**。或者利用专业的硬件设备做负载均衡,比如性能极高的 F5,但价格也极高,入门级的设备都要十几万。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/or1oBlhhkrYKcGgc.webp) 你大为震惊:哎呀,这我可买不起了呀…… 鱼皮:快醒醒吧,这种硬件负载均衡主要用于金融、电信等大型企业,咱们一般用不到。 你突然想到:对了,我听说有些大公司会用 DNS 来做负载均衡,这算是哪一层呢? 鱼皮:问得好,**DNS 负载均衡** 比较特殊。它严格来说属于应用层,但工作原理和前面讲的都不太一样。 传统负载均衡是用户请求已经到达服务器后再分配,而 DNS 负载均衡是在用户浏览器查询域名对应的 IP 地址时,DNS 服务器就根据策略(如地域、负载)返回不同的服务器 IP,从而实现流量分配。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/Y5w2YiXZHmEuWDSP.webp) 它的优点是实现简单、成本低,适合做全球流量分配,比如国内用户访问国内服务器,海外用户访问海外服务器。 缺点是不够灵活,而且 DNS 有缓存,改了配置不能立即生效。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/5eSG8iUKUplkbODc.webp) ### 第四阶段:负载均衡算法 你点点头:那我还是老老实实用七层和四层负载均衡吧。对了,负载均衡器怎么知道把请求分给哪台服务器呢? 鱼皮:这就要靠 **负载均衡算法** 了,算法分两大类 —— 静态算法和动态算法。 静态算法就是按照固定的规则分配。 1)首先是最简单的轮询算法(Round Robin)。就像发扑克牌一样,一张一张轮着来(第一个请求给服务器 A,第二个给服务器 B,第三个给服务器 C,然后又回到服务器 A),发完一轮再来一轮。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/CI6rKLG15O6roNvj.webp) 看起来很公平,但如果服务器性能不一样,有的很闲、有的很忙,怎么办? 2)加权轮询(Weighted Round Robin) 就能解决这个问题,你可以给性能高的服务器设置更高的权重,让它处理更多请求。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/gK6gfIBAMCoQ738r.webp) 你:等等,如果用户第一次请求分配到服务器 A 并保存了登录态,第二次请求分配到服务器 B,登录态不就丢失了么? ![](https://pic.code-nav.cn/post_picture/1601072287388278786/sD1xjQCoqhf1JebU.webp) 鱼皮:没错,能想到这点的你非常棒! 3)我们可以用 IP 哈希(Hash)算法来解决这个问题。根据用户的 IP 地址计算一个哈希值,然后分配到对应的服务器。这样同一个用户的请求总是会分配到同一台服务器,登录态就不会丢了。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/lQR92GwcJsSfBKN0.webp) 不过 IP Hash 也有缺点,如果很多用户来自同一个大局域网,可能会导致流量分配不均哦,所以现在主流还是用 Redis 做共享 Session。这也是面试时的一个考点(Session 一致性问题的解决方案)。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/HgTCfLGY4KgJkvqi.webp) 鱼皮:动态算法更灵活,会根据服务器的实时状态来分配请求。 1)最少连接(Least Connections):哪台服务器当前连接数最少、最闲,就优先把请求分给谁。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/Ejed1z7nbG3pY8Fd.webp) 2)最快响应(Least Response Time):哪台服务器的响应速度最快、干活最麻利,就优先把请求分给谁。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/ps9rSEmPEsypAzKh.webp) 小阿巴:这么多算法,记不住啊!哪个最常用啊? 鱼皮笑道:算法千千万,轮询占一半。实际工作中,大部分场景用轮询或加权轮询就够了。 ### 第五阶段:其他重要知识点 你:那负载均衡器怎么知道后端服务器是否健康呢? 鱼皮:这就是 **健康检查** 机制。负载均衡器会定期(比如每隔几秒)向后端服务器发送心跳请求,检查服务器是否正常响应。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/XJFEcR1O0LIRjV8J.webp) 如果连续多次失败,就认为这台服务器挂了,自动把它从服务器列表中剔除。等服务器恢复后,再自动添加回来。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/ORX286aGGdsq675K.webp) 你:哇,就像医院里的护士定时查房一样,太贴心了吧! 等等,负载均衡器能监测后端服务器、替它们分摊压力,但是万一负载均衡器自己挂了怎么办? 鱼皮:问得好,这就是负载均衡的 **高可用** 问题。 解决办法是部署多个负载均衡器,采用主从模式。主负载均衡器正常工作,从负载均衡器随时待命。它们之间会互相发送心跳包,并共享一个虚拟 IP 地址(VIP)。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/yuXa6OIRPVUjgvaR.webp) 一旦从节点发现主节点没有回应了,就接管这个虚拟 IP,用户访问的还是同一个 IP 地址,所以毫无感知。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/cDTNepUeF2cNfBTH.webp) ### 结尾 你感慨道:哇,原来负载均衡有这么多学问!作用、分类、算法,学到了学到了~ 那…… 我现在算是负载均衡专家了吧?! 鱼皮从裤兜里掏出两个硬币砸到你的头上:想啥呢?!你现在只是了解了负载均衡的思想,但是实际开发中还有很多玩法。对了,我之前在 [编程导航](https://codefather.cn/) 分享过一个 Nginx 学习路线,建议你系统学习一下。 ![](https://pic.code-nav.cn/post_picture/1601072287388278786/PZc2d6pZiJVq9GFt.webp) 你虚心地点点头:好的,狗鱼皮! ![](https://pic.code-nav.cn/post_picture/1601072287388278786/htLnQlGAanMMub5k.webp) ## 更多 💻 编程学习交流:[编程导航](https://www.codefather.cn/) 📃 简历快速制作:[老鱼简历](https://www.laoyujianli.com) ✏️ 面试刷题神器:[面试鸭](https://www.mianshiya.com) 📖 AI 学习指南:[AI 知识库](https://ai.codefather.cn/)

关于浏览器存不住cookie的问题

**场景**:前端域名配置了ssl证书,Nginx使用反向代理进行转发,配置如下 ```js #反向代理-START location ^~ /backend/ { proxy_pass http://127.0.0.1:8668/; # 指向后端端口 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #反向代理-END ``` pc端访问域名:https://xxx.xxxxxx.xxxx 进行登录 前端发送了两个请求,分别为 - 登录请求:https://xxx.xxxxxx.xxxx/backend/api/user/login - 获取当前登录用户信息请求:https://xxx.xxxxxx.xxxx/backend/api/user/login 第一个登录请求返回了用户信息,但第二个请求却是无权限,直接回到了登录页面 **排查**:经过排查发现,登录接口返回的响应头返回了Cookie ``` set-cookie: JSESSIONID=A054FD308D135F5948AA22C8A9CA1218; Max-Age=2592000; Expires=Sun, 14 Dec 2025 06:29:53 GMT; Path=/backend/api; HttpOnly ``` 但在获取用户信息的请求中还是无权限,且又返回了一遍Cookie **分析**:后端服务在 /api/user/login 接口成功登录后,返回了一个 Set-Cookie 响应头。 在获取用户信息时前端的实际请求为`https://xxx.xxxxxx.xxxx/backend/api/user/get/login` 当这个请求到达 Nginx 时,location ^~ /backend/ 规则会生效,将请求转发到 `http://127.0.0.1:8668/` - **Nginx 收到的路径**:`/backend/api/user/get/login` - **转发到后端的路径**:`/api/user/get/login` 浏览器要发送 https://xxx.xxxxxx.xxxx/backend/api/user/get/login 请求时,会检查自己的 Cookie 仓库。 它发现有一个`cookie`,其 Path 是 `/api` 浏览器会将当前请求的路径 (/backend/api/user/get/login) 与 Cookie 的 Path (/api) 进行比较 浏览器只会在请求路径以 /api 值开头 时才发送该 Cookie 但`/backend/api/user/get/login`不是以`/api/`开头的,所以浏览器决定不发送cookie 这才导致了无权限的问题 **解决**:修改 Nginx 配置 不改变后端的任何代码,通过调整 Nginx 配置,让浏览器认为 /backend 目录下的所有请求都应该带上 Path=/api 的 Cookie 在反向代理的配置中,增加一个`proxy_cookie_path`指令,其作用为: - 如果发现响应头中有 `Set-Cookie`,并且其 Path 属性值为 `/api`,Nginx 就会将其修改为 `/backend/api`,再发送给浏览器。 - 浏览器收到的 `Set-Cookie` 就变成了:`JSESSIONID=...; Path=/backend/api; ...` - 当下次浏览器请求 `/backend/api/user/get/login` 时,路径是以 `/backend/api` 开头的,所以它会正确地带上 Cookie 反向代理配置修改后如下: ``` #反向代理-START location ^~ /backend/ { proxy_pass http://127.0.0.1:8668/; proxy_cookie_path /api /backend/api; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #反向代理-END ``` 此时再次测试登录,问题完美解决

一个域名就够了:部署多个项目的终极指南 (5分钟上手)

## 一、需求背景 + 作为独立开发者,秉持”能省则省“的原则,可以通过一些手段实现同样的效果; + 在实际的业务开发过程中,确实涉及到这样的场景,如在门户网站开发完成部署测试时给金主爸爸预览的时候,有时候带域名部署,若有修改这时候我们就会将项目划分成多个,这时候xxx.com/v1、xxx.com/v2、xxx.com/v3等等。这样既保留了工作记录,又会给甲方提供一定的情绪价值(讲个笑话,别当真); + <font style="color:rgb(33, 37, 41);">公司没钱,资源紧张,域名少,域名临时没有申请下来,不够用。这个时候,我们需要把子项目给做相应的修改。</font> <font style="color:rgb(33, 37, 41);"></font> ![008CBF30.jpg](https://pic.code-nav.cn/post_picture/1643218270658023426/0kBSafaNNZr32Ss0.jpg) ## <font style="color:rgb(33, 37, 41);">二、最终效果</font> 示例 + 个人博客网站:[https://zhydoc.com](https://zhydoc.com/) + 鱼总的云图库网站:[https://zhydoc.com/picture](https://zhydoc.com/picture) ## 三、实现步骤 ### 1、此处默认认为读者已经掌握Nginx部署单个项目的能力 ![](https://pic.code-nav.cn/post_picture/1643218270658023426/8atCQFwr54dCrKZ6.webp) ### 2、<font style="color:rgb(33, 37, 41);">子项目的vite.config.js文件的base添加区分其他项目的前缀,比如/picture/,同时在路由文件中也进行相应的修改</font> ![](https://pic.code-nav.cn/post_picture/1643218270658023426/aJVBBPzqIy3TvaJo.webp) ![](https://pic.code-nav.cn/post_picture/1643218270658023426/D8HFTxEke335fdZ6.webp) ### 3、我说白了,我白说了,其实就是达成的效果就是将‘/’变成‘/picture/’,至于怎么实现,需要根据对应的前端框架的版本以及打包工具进行确定 ### 4、修改nginx配置,以下为关键配置信息 ```xml location / { root html/main/dist/; index index.html index.htm; try_files $uri $uri/ /index.html; } location /picture { alias html/picture/dist/; try_files $uri $uri/ /picture/index.html; } ``` ### 5、<font style="color:rgb(33, 37, 41);">检查子项目中,是否有未能够添加到/picture/前缀的需要手动修改一下,添加/picture/前缀</font> <font style="color:rgb(33, 37, 41);">至此,恭喜你学会了:同一个域名下,部署多个项目...</font> ![](https://pic.code-nav.cn/post_picture/1643218270658023426/xRlG7L7HuwLB4eJN.jpg)

nginx 简单配置:

b. nginx 配置详解: -------------- <img src="https://pic.code-nav.cn/post_picture/1608648175386624001/zHxLLYdQ9KoioV9U.webp" alt="AvSDZYoWcw0WxbZ.jpeg" width="100%" /> 跳转[:](https://blog.csdn.net/sheep_fur/article/details/148034942?spm=1011.2415.3001.5331) https://blog.csdn.net/sheep_fur/article/details/148034942?spm=1011.2415.3001.5331 ### ⅰ. http 块 这里我一般只配置个 gzip 原因: 当图片资源多时 会导致加载缓慢 解决: 使用gzip 压缩资源 可以减少加载耗时 ```xml http{ gzip on #开启gzip .....其他配置 } ``` ### ⅱ. sever 块 #### 1. 作用 定义一个虚拟机 可以在支持多个域名 #### 2. listen 指定nginx要监听的端口 就是浏览器访问哪个端口可以到 nginx 上面 #### 3. server_name 指定服务器的名称 localhost 或者 你的域名 #### 4. root(可选) 指定网页文件的根目录在哪 后面跟你的前端dist文件的路径 (可选) 可以在location里面详细指定 也可以在server块全局指定 #### 5. index(可选) 指定默认的首页文件 一般都是 index.html (可选) 可以在location里面详细指定 也可以在server块全局指定 #### 6. 配好后的server 效果 这一part配好后应该是这样: ```xml server{ listen 8083 server_name localhost(或者是你的域名 xx.xx.xx.xx) root /路径/路径/dist (可选) index index.html (可选) } ``` ### ⅲ. location 块 #### 1. 作用 实现URL 到 文件系统的映射 可以根据URL 来匹配相应的配置 #### 2. location 后面的 / ```xml location /{ ......剩余配置 } eg: 比如不管是 localhost:8083/xxxxx/xxxx/xxxx 还是localhost:8083/xxxxx/xxxx/xxxx/xxx/xxxx 都会走这个路径 ``` / 表示: 只要是/开头的 路径从端口号起后面的所有URL 都会被配到这个 location 上面 #### 3. root 可以进一步指定该location下的文件路径 #### 4. index 指定该location下的首页文件 index.html #### 5. proxy_pass 反向代理 指定反向代理的转发方向 **后面跟后端接口的地址** **反向代理**: **不知道后端服务器的存在** 如发给前端服务器的请求被反向代理到后端服务器后端的端口 **正向代理**: **知道后端服务器的存在** 如用魔法 将给服务器的消息由代理服务器转发 ```xml location /api { proxy_pass 你的后端地址 #这里还有一些其他的配置 很简单 proxy_redirect default; proxy_http_version 1.1; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 90s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ``` #### 6. try_files (解决nginx 路由匹配不到) **问题: 当部署路由项目时 跳转时会出现找不到路由页面的情况** try_files 尝试匹配文件目录 \ try_files 后面跟 $uri $uri/ /index.html; 匹配不到跳转到 /index.html 也可以 $uri $uri/ = 404 匹配不到返回404 #### 7. 配好后的 location 效果 ```xml location /{ root 你的资源路径; index index.html; #如果解决路由访问问题 #try_files $uri $uri/ /index.html; } location /api{ proxy_pass 你的后端地址; #这里还有一些其他的配置 很简单 proxy_redirect default; proxy_http_version 1.1; proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 90s; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } ```

BI项目部署的nginx反向代理问题

### 问题 部署BI项目,服务器使用了nginx反向代理解决跨域,但是不知道为什么配置nginx会将端口号吃掉。如下图 <img src="https://pic.code-nav.cn/post_picture/1795112770781884417/zFqZlgxkXbWG5S4T.webp" alt="image.png" width="100%" /> ### nignx的配置如下 <img src="https://pic.code-nav.cn/post_picture/1795112770781884417/aO58cIQ7j82Mvqd2.webp" alt="image.png" width="100%" /> ### 前端传递的默认路径 <img src="https://pic.code-nav.cn/post_picture/1795112770781884417/fCAgsLGWcdc03TK2.webp" alt="image.png" width="100%" /> 列出你计划或已经开始学习的内容和资源。比如:“正在学习《Java 编程思想》这本书,已经完成了前两章。” ### 反向代理 我理解的反向代理,前端向nginx 80端口发送请求http://localhost:80/api/user/login 然后 因为nginx的配置会拦截到/api,从而重定向路径 http://localhost:8080/api/user/login ### 已有尝试 调查了很多方法都失败了,不知道为什么现在我访问就会将端口号丢失 ### 期望帮助 希望大佬帮忙看一下,指点指点,感激不尽啊 ### 相关资料 nginx参考资料:https://blog.csdn.net/qq_37568918/article/details/121167951

服务器上部署一个前端项目

## 服务器上部署一个前端项目 ### 1. 在 Ubuntu 上安装 Docker #### 步骤 1:更新软件包索引 ``` sudo apt-get update ``` - **`sudo`**:以超级用户权限运行命令,允许执行需要更高权限的操作。 - **`apt-get`**:Ubuntu 和 Debian 系统的包管理工具。 - **`update`**:更新本地的软件包索引,确保获取到最新的软件包信息。 #### 步骤 2:安装必要的包 ``` sudo apt-get install apt-transport-https ca-certificates curl software-properties-common ``` - **`install`**:安装指定的软件包。 - **`apt-transport-https`**:允许 `apt` 使用 HTTPS 协议,确保下载的软件包是安全的。 - **`ca-certificates`**:使得系统能够验证 SSL 证书,确保安全连接。 - **`curl`**:用于下载文件和网页内容的命令行工具。 - **`software-properties-common`**:提供 `add-apt-repository` 命令,方便管理软件源。 #### 步骤 3:添加 Docker 的官方 GPG 密钥 ``` curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - ``` ​ 从指定 URL 下载文件,参数含义如下: - `f`:如果发生错误,`curl` 将不输出错误信息。 - `s`:以静默模式运行,不显示进度。 - `L`:如果 URL 被重定向,`curl` 将自动跟随重定向。 - **`|`**:管道符,将 `curl` 下载的内容作为输入传递给后面的命令。 - **`sudo apt-key add -`**:将下载的 GPG 密钥添加到系统中,以验证软件包的合法性。 #### 步骤 4:添加 Docker 仓库 ``` sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" ``` - **`add-apt-repository`**:添加新的软件源。 - **`"deb [arch=amd64] ..."`**:指定新仓库的格式和位置,`deb` 表示这是一个二进制包。 - **`$(lsb_release -cs)`**:自动获取当前 Ubuntu 版本的代号(例如,bionic、focal),以确保添加适合该版本的软件源。 - **`stable`**:指定要使用的版本(稳定版)。 #### 步骤 5:再次更新软件包索引 ``` sudo apt-get update ``` - 重新执行此命令以更新软件包索引,包含刚刚添加的 Docker 仓库。 #### 步骤 6:安装 Docker ``` sudo apt-get install docker-ce ``` - **`install`**:安装指定的软件包。 - **`docker-ce`**:安装 Docker Community Edition,Docker 的开源版本。 #### 步骤 7:启动 Docker 并设置开机自启动 ``` sudo systemctl start docker sudo systemctl enable docker ``` - **`systemctl start docker`**:启动 Docker 服务,使其在后台运行。 - **`systemctl enable docker`**:设置 Docker 服务为开机自动启动,这样每次重启服务器时 Docker 服务会自动启动。 #### 步骤 8:验证 Docker 安装 ``` sudo docker run hello-world ``` - **`docker run`**:启动一个新的 Docker 容器。 - **`hello-world`**:这是一个测试镜像,用于验证 Docker 是否正确安装并能正常运行。运行该命令会下载并执行该镜像,显示成功消息。 ### 2.安装NGINX #### **拉取镜像** ``` docker pull nginx:1.24.0 ``` #### **运行容器** ``` docker run --name nginx -p 80:80 -d nginx:1.24.0 ``` #### **创建本地挂载的目录** ``` mkdir -p /docker/nginx/conf mkdir -p /docker/nginx/log mkdir -p /docker/nginx/html ``` #### **复制运行的nginx配置到宿主机上** ``` 将容器nginx.conf文件复制到宿主机 docker cp nginx:/etc/nginx/nginx.conf /docker/nginx/conf/nginx.conf 将容器conf.d文件夹下内容复制到宿主机 docker cp nginx:/etc/nginx/conf.d /docker/nginx/conf/conf.d 将容器中的html文件夹复制到宿主机 docker cp nginx:/usr/share/nginx/html /docker/nginx/ 将容器中的日志log文件夹复制到宿主机 docker cp nginx:/var/log/nginx/ /docker/nginx/log ``` #### **上述命令执行完毕删除运行的容器** ``` docker stop 容器id docker rm 容器id ``` #### **正式运行** ``` docker run -p 80:80 -p 5010:5010 --restart=always --name nginxWeb -v /docker/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /docker/nginx/conf/conf.d:/etc/nginx/conf.d -v /docker/nginx/log:/var/log/nginx -v /docker/nginx/html:/usr/share/nginx/html -d nginx:1.24.0; ``` #### 配置NGINX配置文件 cd进入到conf/conf.d/default.conf中区编辑 ##### 配置多个server去部署多个项目 ``` server { listen 80; listen [::]:80; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html/build; index index.html index.htm; try_files $uri $uri/ /index.html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } server { listen 5010; listen [::]:5010; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html/dist; index index.html index.htm; try_files $uri $uri/ /index.html; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } ``` ##### 配置一个server去部署多个项目 ``` server { listen 80; listen [::]:80; server_name localhost; client_max_body_size 100M; # Adjust this size as needed # 官网静态页面 (默认主页) location / { root /usr/share/nginx/html/gw_web; index index.html index.htm; try_files $uri $uri/ /index.html; } # Java 后端服务(代理到9001端口) location /compute { proxy_pass http://172.19.400.108:9001/jiutuai/api1/; # 反向代理到 Java 服务,记得结尾需要加上/ proxy_set_header Host $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; } # Python 后端服务(代理到5000端口) location /tupu { proxy_pass http://localhost:5000; # 反向代理到 Python 服务 proxy_set_header Host $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; } # 知识图谱前端页面(5010端口对应的前端) location /kg { alias /usr/share/nginx/html/kg/dist; index index.html index.htm; try_files $uri $uri/ /kg/index.html; # SPA 路由处理 } # AI 书籍前端页面(9003端口对应的前端) location /ai_book { alias /usr/share/nginx/html/ai_book/dist; index index.html index.htm; try_files $uri $uri/ /ai_book/index.html; # SPA 路由处理 } # 错误页面配置 error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } ``` #### 重启NGINX容器 ``` docker restart id ```

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

首先 F12 看 login 接口对应的网络请求有没有 ⚠️,如果有那是后端的问题,如果没有那是前端的问题 ## 前端问题 前端没有携带 cookie 导致后端识别不到 1) 前端 axios 是否开启了 withCredentials=true 2) 在 OpenAPI 的那边配置项,设置下 withCrendential <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/gW4aFU1njcXhhvtN.webp" alt="img" width="100%" /> ## 后端问题 确认环境 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** <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/g0R8KeESvB5cNcOZ.webp" alt="image.png" width="100%" /> > 前端请求地址和前端运行地址一致 也就是前端 baseURL 请求 192.168.196.158:8000 具体参考自己运行地址 后端跨域配置 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/21pbGbVFQ5w1QIn7.webp" alt="image.png" width="100%" /> 需要修改宝塔具体位置 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/rhdSmndvZtGBZ6Yh.webp" alt="image.png" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/oQ38EqG7a4mdjyeR.webp" alt="image.png" width="100%" /> 如果是原生的 Nginx 下面是完整的代码,如果是宝塔的话只需要复制两个 `location` 模块到前端配置文件即可 ,**注意一定不要换顺序!** ``` 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 比如,下面这种情况: <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/E6qnVzu2ALVtOTiN.webp" alt="image.png" width="100%" /> 所以会导致跨域失败! > 解决方法:前端的 baseUrl 修改成前端运行地址 #### Hard 跨域配置 1、如果之前使用的是下面这种跨域方式也要删除掉/注释! <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/eDZMvNA4CQtfbmsG.png" alt="image.png" width="590px" /> 2、这种方式是前端请求一个独立于前端和后端的端口,比如 前端 80 后端 8080 ,那么前端请求 90 端口让 90 对端口进项反向代理到后端 3、上面的 easy 方式虽然简单,但是如果后端想要使用独立的子域名的情况下就不适用了 --- <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/NJN3DmEuksQN2umo.webp" alt="image-20240914115007224" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/mqafC2zfCRO7NcYm.webp" alt="image-20240914115143570" width="100%" /> ```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; } } ``` 请求流程图 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/pbK8y7G4dTiM88WC.webp" alt="image.png" width="100%" /> 使用域名 前端请求后端的域名,然后在 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 的端口)而不是直接请求后端实际运行端口 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/nIMHYqIdfUjDuCxz.webp" alt="image.png" width="100%" /> 2) 直接请求后端端口,那么 Nginx 就失去了存在的意义! 3)宝塔 + 服务器放行 `90` 端口,这个要注意!!(具体看自己写的是哪个端口) 4)完成 添加 nginx 配置 + 放行端口 正常就没什么问题了! 5)后端配置文件如果写了 samesite 或者 sercure 属性要删除掉! <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/OxyP89FpOL9rkP9n.webp" alt="image.png" width="100%" /> 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 之类的),当然也不用单独再配置一个前端项目 类似这种 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/KQuO0VVOVab2dchO.webp" alt="image.png" width="100%" /> ```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 是关键: ``` 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 的端口,不要直接请求实际端口 !!!

nginx把docker中的server_name 配置成localhost,为什么配置会生效

### 问题描述 看到一个案例在服务器上把nginx(docker中)的server_name配置成了localhost,并不是服务器的ip或者域名,但是请求的时候再浏览器输入服务器的ip和端口nginx能够准确的完成反向代理和动静分离,自己试了半天也没成功 ### 背景信息 nginx配置 ### 具体疑问 为什么docker中的nginx的server_name配置成localhost能正确完成工作

开启 HTTPS 详细教程

# 前提 1. 服务器 2. 域名 3. 备案 # 域名 购买域名的时候需要注意,不需要买 **专业版DNS解析** 如果不知道这个东西大概率没有需求! <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/bRHtliYJT4FSK4hG.webp" alt="image-20240905145519033" width="100%" /> ## 域名的不同层级 顶级域名(TLD)和二级域名是域名结构中的不同层级。 1. **顶级域名 (TLD)**:这是域名的最高层级,通常位于域名的最后部分,比如 `.com`、`.org`、`.net`、`.cn` 等等。每个域名都必须有一个顶级域名。 2. **二级域名 (SLD)**:这是顶级域名前的部分,通常是你注册的名称,用于识别网站或组织。比如在 `example.com` 中,`example` 就是二级域名。 3. **二级域名的子域名**(通常称为**子域名**):是在二级域名前再加一部分,比如 `api.example.com` 中的 `api` 就是子域名。 举例来说: - **顶级域名**:`com` 是顶级域名。 - **二级域名**:`example.com` 是二级域名,其中 `example` 是二级域名的具体名称,`.com` 是顶级域名。 - **子域名**:`api.example.com` 中的 `api` 是 `example.com` 的子域名。 ## 域名 和 SSL 关系 域名是互联网上用于标识网站或服务的唯一地址,比如 `example.com`。它分为多个层级,常见的有顶级域名(TLD,比如 `.com`、`.org`)和二级域名(如 `www.example.com` 中的 `www`)。二级域名通常用来表示同一域名下的不同子网站或服务。 关于 SSL 证书,每一个二级域名是否需要单独的 SSL 证书取决于你使用的证书类型: 1. **单域名 SSL 证书**:只保护一个特定的域名,比如 `example.com`,但**不能保护二级域名**(如 `sub.example.com`)。 2. **多域名 SSL 证书(SAN 证书)**:可以保护多个不同的域名,包括二级域名,但需要你在申请时列出这些域名。 3. **通配符 SSL 证书**:可以保护一个主域名及其所有二级域名,比如 `*.example.com`,这意味着它同时保护 `www.example.com`、`api.example.com` 等等。 如果你有很多二级域名,使用通配符证书可以简化 SSL 证书管理,否则每个二级域名都需要单独的 SSL 证书。 所以我们使用 **通配符 SSL 证书** ,如果不用通配符那么就需要单独为 leikooo.com 和 api.leikooo.com 申请**两个** SSL 证书,当然流程都是一样的,下面就用 通配符 SSL 做演示! # 申请 SSL 我是用的第三方的 SSL 当然腾讯、阿里的 SSL 都是可以的,但是要注意一件事:域名 + 服务器 一定要是同一家的,不然可能会出问题! [OHTTPS](https://ohttps.com/) 1、 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/TxMu5hjTT0388YdW.webp" alt="image-20240906171340574" width="100%" /> 2、 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/m6m0Auun46a7Jv3u.webp" alt="image-20240905152726826" width="100%" /> 他有一个 365 天的**付费**证书,但是不需要,选择后面的 90 天的**免费证书**就行 > 输入的域名:`*.leikooo.com` 不要照抄我的,写自己买的域名 3、 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/hp8VYGokvfkvBCkq.webp" alt="image-20240905153442323" width="100%" /> 4、 比如我的: 主机记录:_acme-challenge.leikooo.com 记录值: _acme-challenge.3ejqm8pg2678gd7n.ohttps.com <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/ixeftXGlerSvTlYD.webp" alt="image-20240905154713249" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/0faKdoW55IhRwytO.webp" alt="image-20240905154039301" width="100%" /> 域名后台: 1. 主机记录,只需要写 _acme-challenge (看自己的是什么,这里只是演示) 2. 记录类型选择 `CNAME` 3. 记录值 直接 CV 就行 5、检查是否创建成功 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/m2D73ngInRLCgXZt.webp" alt="image-20240905154504516" width="100%" /> 6、等一会~ <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/ZPMOkbFU8Qvg3Rdv.webp" alt="image-20240905154539380" width="100%" /> 7、创建成功! <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/qGPjaLeEZKCWKzVo.webp" alt="image-20240905154809961" width="100%" /> 8、转换格式方便后端部署使用 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/9us3zYlUg144dSoB.webp" alt="image-20240905155317708" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/ueoacRaG6ExFAY1m.webp" alt="image-20240905155422413" width="100%" /> 证书格式网站:https://myssl.com/cert_convert.html <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/6lhOrjIaHP3KkTfv.webp" alt="image-20240905155854597" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/dvRgt8F1qCLOEERe.webp" alt="image-20240905160034621" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/1MTPgdo1ogCVXiWt.webp" alt="image-20240906170535088" width="100%" /> 9、下载 `.key` 后缀文件、和 `.cer` 后缀文件 方便后面原生 Nginx 部署时使用 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/iHpQPqQ4yKKRXogY.webp" alt="image-20240906145825556" width="100%" /> # 必要设置 ## 宝塔 1、宝塔安装 Nginx <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/7jdJmvHADI2cyP94.webp" alt="image-20240906153814080" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/Yxamp1Z5zgVXN1MG.webp" alt="image-20240906153855695" width="100%" /> 2、添加前端项目 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/EdRldrO52254xEy4.webp" alt="image-20240906155150856" width="100%" /> > 域名根据自己实际情况填写 3、添加关于后端的项目 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/2sA1aIa2f8Bfp0qU.webp" alt="image-20240906155100325" width="100%" /> 4、设置证书和密钥 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/Y3ilLn8j1iDsn7MM.webp" alt="image-20240906161038215" width="100%" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/OhknHsydizrHcid5.webp" alt="image-20240906161045353" width="100%" /> > 后端网站也是按照这个流程上传 key 和 cer 5、后端站点设置反向代理,前端站点选中打包上传的目录 前端站点: <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/GSpRQrRcjpuxhc55.webp" alt="image-20240906161321594" width="100%" /> 后端站点 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/FQGb8GNe0tsbi2xK.webp" alt="image-20240906161512514" width="100%" /> 小插曲,直接访问 接口文档出现下面的情况 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/YO0pkdiodu2fVmv7.png" alt="image-20240906165028439" width="574px" /> 解决办法:需要把上面默认目标URL 改成 https 最终效果 > 比如我的后端项目运行在 9090 端口我就可以这样写 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/VuXLK0bYGjb0hi6T.webp" alt="image-20240906165328644" width="666px" /> <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/GFNDuDPGfqWgRETN.png" alt="image-20240906165614339" width="100%" /> ## 原生 Nginx + 安装 Nginx [教程](https://www.codefather.cn/post/1824822454893486081) + 可以参考一下 跨域 + SSL 的[Nginx 文件](https://codecopy.cn/post/qrpwz3) 1、创建一个文件夹放 key、cer 文件 ```cmd cd ~ mkdir key ``` 2、把之前下载好的 key 、cer 文件上传到服务器的 `/root/key` 文件夹,也就是我们上面创建好的文件夹 1)`rz` 命令 2)WinSCP 3)其他支持上传的工具 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/XnwLKkAO546TIEqR.png" alt="image-20240906163852454" width="543px" /> 3、查看 Nginx 配置文件 ```nginx nginx -t ``` 如果报错 `command not found` 就看上面的安装教程,设置一下**环境变量**就好 <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/0T1aoB9dxBsuZCFZ.png" alt="image-20240906163413542" width="100%" /> 4、修改 Nginx 配置文件 ``` vi /usr/local/nginx/conf/nginx.conf ``` ```nginx server { # 把 80 改成 443 ssl listen 443 ssl; server_name www.leikooo.cn leikooo.cn; # ssl 最后的文件名根据实际情况修改 ssl_certificate /usr/key/fullchain.cer; ssl_certificate_key /usr/key/cert.key ; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; root /root/project/fronted; location / { index index.html index.htm; try_files $uri $uri/ /index.html; } } # 如果使用 http 转到 https server { listen 80; server_name www.leikooo.cn leikooo.cn; return 301 https://$server_name$request_uri; } ``` ```nginx server { listen 443 ssl; server_name api.leikooo.cn; # ssl 和上面的几乎一项 ssl_certificate /usr/key/fullchain.cer; ssl_certificate_key /usr/key/cert.key ; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; location / { # 反向代理,根据自己后端实际运行地址端口修改 proxy_pass https://localhost:9090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` # 前端 前端其实对于 Https 需要代码修改的部分不多,主要就是修改访问后端的地址(修改 baseURL 找不到全局搜索): ``` /** * @name request 配置,可以配置错误处理 * 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。 * @doc https://umijs.org/docs/max/request#配置 */ export const request = { baseURL: 'https://api.leikooo.com', withCredentials: true, ...errorConfig, }; ``` <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/HJBucq0P0vuqAMjq.png" alt="image.png" width="318px" /> # 后端 + 需要格式 JKS + 需要文件密码 (上面证书格式转化时候填写的密码) 1、修改配置文件 ```yml server: ssl: key-store: classpath:_.leikooo.com.jks key-store-type: JKS key-store-password: 密码 ``` > _.leikooo.com.jks 这个具体是 jks 文件名称,自己是什么就填写什么就好 2、 需要把 jks 文件,放到 `resource` 目录下面 ``` ├─java └─resources ├─_.leikooo.com.jks ``` <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/B81bJ74tcXoVsc8N.webp" alt="image-20240906150703646" width="366px" /> 3、然后打包上传到服务器上,运行就好了! 4、访问线上接口文档,可以发现是 HTTPS 了! <img src="https://pic.code-nav.cn/post_picture/1608460212774109186/pobTCY6Wet2G7jRP.png" alt="image-20240906151106212" width="315px" />

下载 APP