最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Nginx反向代理之域名轉(zhuǎn)發(fā)與路徑重寫配置指南

 更新時(shí)間:2026年07月10日 08:44:48   作者:知遠(yuǎn)漫談  
在現(xiàn)代互聯(lián)網(wǎng)架構(gòu)中,反向代理早已不再是可選技能,而是構(gòu)建高可用、高性能、安全穩(wěn)定服務(wù)的核心基石,本文將帶你深入 Nginx 反向代理的進(jìn)階世界,系統(tǒng)性地解析域名轉(zhuǎn)發(fā)與路徑重寫兩大核心機(jī)制,需要的朋友可以參考下

引言

在現(xiàn)代互聯(lián)網(wǎng)架構(gòu)中,反向代理早已不再是“可選技能”,而是構(gòu)建高可用、高性能、安全穩(wěn)定服務(wù)的核心基石。Nginx 作為最流行的反向代理服務(wù)器之一,憑借其輕量、高效、模塊化的設(shè)計(jì),成為無(wú)數(shù)企業(yè)級(jí)應(yīng)用的首選。然而,許多開發(fā)者對(duì) Nginx 的理解仍停留在“簡(jiǎn)單轉(zhuǎn)發(fā)”層面——proxy_pass http://localhost:8080; 就是全部。殊不知,真正的力量在于精準(zhǔn)控制流量的流向與形態(tài):如何根據(jù)域名動(dòng)態(tài)路由?如何將 /api/v1/user 透明重寫為 /user-service/api/v1/user?如何在不修改后端代碼的前提下,實(shí)現(xiàn)多租戶、灰度發(fā)布、API 網(wǎng)關(guān)式管理?

本文將帶你深入 Nginx 反向代理的進(jìn)階世界,系統(tǒng)性地解析域名轉(zhuǎn)發(fā)路徑重寫兩大核心機(jī)制。我們將從基礎(chǔ)語(yǔ)法講起,逐步過(guò)渡到復(fù)雜場(chǎng)景實(shí)戰(zhàn),結(jié)合真實(shí) Java 后端服務(wù)示例,展示如何通過(guò) Nginx 實(shí)現(xiàn)無(wú)侵入式架構(gòu)升級(jí)。你將學(xué)會(huì)如何用幾行配置,讓一個(gè)原本只能訪問(wèn) http://app.example.com:8080 的 Spring Boot 服務(wù),對(duì)外表現(xiàn)為 https://api.yourcompany.com/v1/users,同時(shí)還能自動(dòng)處理負(fù)載均衡、SSL 終止、緩存策略和安全頭注入。

無(wú)論你是運(yùn)維工程師、后端開發(fā)者,還是全棧架構(gòu)師,掌握這些技能都將極大提升你對(duì)系統(tǒng)流量的掌控力。準(zhǔn)備好了嗎?讓我們開啟這場(chǎng)從“能用”到“優(yōu)雅”的進(jìn)階之旅

一、反向代理基礎(chǔ):理解 Nginx 的流量入口

在深入域名轉(zhuǎn)發(fā)與路徑重寫之前,我們必須先厘清一個(gè)根本問(wèn)題:Nginx 是如何“代理”請(qǐng)求的?

想象一下,你的用戶通過(guò)瀏覽器訪問(wèn) https://api.example.com/users。這個(gè)請(qǐng)求首先抵達(dá)的是 Nginx 服務(wù)器(監(jiān)聽 443 端口),而非你的 Java 應(yīng)用(運(yùn)行在 8080 端口)。Nginx 接收請(qǐng)求后,根據(jù)配置規(guī)則,決定“把這個(gè)問(wèn)題交給誰(shuí)處理”——可能是本地的 Tomcat,也可能是遠(yuǎn)在 AWS 的微服務(wù)集群。這個(gè)“中間人”角色,就是反向代理的本質(zhì)。

1.1 最基礎(chǔ)的 proxy_pass 配置

server {
    listen 443 ssl;
    server_name api.example.com;
    ssl_certificate /etc/ssl/certs/api.example.com.crt;
    ssl_certificate_key /etc/ssl/private/api.example.com.key;
    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

這段配置看似簡(jiǎn)單,實(shí)則暗藏玄機(jī):

  • listen 443 ssl;:監(jiān)聽 HTTPS 請(qǐng)求
  • server_name api.example.com;:匹配請(qǐng)求頭中的 Host 字段,確保只有訪問(wèn)該域名的請(qǐng)求才會(huì)被處理
  • location / { ... }:匹配所有路徑(根路徑)
  • proxy_pass http://localhost:8080;:將請(qǐng)求轉(zhuǎn)發(fā)到本地 8080 端口的 Java 服務(wù)

關(guān)鍵點(diǎn)proxy_pass 后面的 URL 是否包含路徑,決定了 Nginx 如何處理原始請(qǐng)求路徑!

1.2 路徑拼接陷阱:帶路徑 vs 不帶路徑

這是新手最容易踩的坑!

情況一:proxy_pass不帶路徑

location /api/ {
    proxy_pass http://backend:8080;  # 注意:沒(méi)有尾部 /
}

請(qǐng)求:https://api.example.com/api/v1/users
→ Nginx 轉(zhuǎn)發(fā)為:http://backend:8080/api/v1/users

行為:Nginx 將 location 匹配的部分(/api/原樣保留,拼接到目標(biāo) URL 后面。

情況二:proxy_pass帶路徑

location /api/ {
    proxy_pass http://backend:8080/service/;  # 注意:有尾部 /
}

請(qǐng)求:https://api.example.com/api/v1/users
→ Nginx 轉(zhuǎn)發(fā)為:http://backend:8080/service/v1/users

行為:Nginx 會(huì)移除 location 中匹配的路徑部分(/api/),然后將剩余部分(v1/users)拼接到 proxy_pass 的路徑之后(/service/)。

情況三:錯(cuò)誤組合(不帶 / 的 location + 帶路徑的 proxy_pass)

location /api {  # 沒(méi)有尾部 /
    proxy_pass http://backend:8080/service/;  # 有尾部 /
}

請(qǐng)求:https://api.example.com/api/v1/users
→ Nginx 轉(zhuǎn)發(fā)為:http://backend:8080/service/v1/users ?(看似正常)

但請(qǐng)求:https://api.example.com/api(無(wú)尾部)
→ Nginx 轉(zhuǎn)發(fā)為:http://backend:8080/service ?

問(wèn)題來(lái)了:如果后端服務(wù)期望 /api 作為路徑前綴,而你卻在 proxy_pass 中重寫了它,那么后端代碼中 @RequestMapping("/api") 的路徑將永遠(yuǎn)無(wú)法匹配,因?yàn)檎?qǐng)求到達(dá)時(shí)已經(jīng)變成了 /service。

最佳實(shí)踐

  • 如果 location/ 結(jié)尾 → proxy_pass 也以 / 結(jié)尾
  • 如果 location 不以 / 結(jié)尾 → proxy_pass 也不應(yīng)帶路徑
  • 強(qiáng)烈建議:統(tǒng)一使用帶 / 的寫法,語(yǔ)義清晰,避免歧義

1.3 Java 后端如何感知真實(shí)請(qǐng)求?

Nginx 作為代理,會(huì)“隱藏”客戶端的真實(shí) IP、協(xié)議、主機(jī)名。如果你的 Java 應(yīng)用(如 Spring Boot)需要記錄訪問(wèn)日志、做權(quán)限校驗(yàn)、生成完整 URL,就必須依賴 Nginx 傳遞的頭部信息。

@RestController
@RequestMapping("/api/v1")
public class UserController {
    @GetMapping("/users")
    public ResponseEntity<String> getUsers(
            HttpServletRequest request) {
        String clientIp = request.getHeader("X-Real-IP");
        String forwardedHost = request.getHeader("Host");
        String scheme = request.getHeader("X-Forwarded-Proto");
        System.out.println("Client IP: " + clientIp);
        System.out.println("Original Host: " + forwardedHost);
        System.out.println("Protocol: " + scheme);
        return ResponseEntity.ok("Hello from Java backend!");
    }
}

對(duì)應(yīng)的 Nginx 配置必須包含:

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;

為什么需要 X-Forwarded-For?
因?yàn)榭蛻舳苏鎸?shí) IP 可能經(jīng)過(guò)多層代理(CDN、負(fù)載均衡器等),$proxy_add_x_forwarded_for 會(huì)追加每一層的 IP,形成鏈?zhǔn)接涗?,如?code>192.168.1.10, 10.0.0.5, 172.16.0.1

實(shí)際項(xiàng)目中,Spring Boot 可通過(guò) server.forward-headers-strategy=native + spring-boot-starter-web 自動(dòng)識(shí)別這些頭,無(wú)需手動(dòng)解析。但理解其原理,對(duì)排查問(wèn)題至關(guān)重要。

二、域名轉(zhuǎn)發(fā):一個(gè) Nginx 實(shí)例,服務(wù)多個(gè)業(yè)務(wù)域

現(xiàn)實(shí)世界中,很少有系統(tǒng)只服務(wù)一個(gè)域名。你可能有:

  • api.yourcompany.com → 提供 REST API
  • admin.yourcompany.com → 管理后臺(tái)
  • static.yourcompany.com → 靜態(tài)資源
  • legacy.yourcompany.com → 舊系統(tǒng)遷移中

Nginx 的 server 塊可以定義多個(gè),每個(gè) server_name 對(duì)應(yīng)一個(gè)獨(dú)立的虛擬主機(jī)。這是實(shí)現(xiàn)多租戶、多服務(wù)統(tǒng)一入口的核心手段。

2.1 多域名基礎(chǔ)配置示例

# 1. API 服務(wù)
server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;
    location / {
        proxy_pass http://api-backend:8080;
        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;
    }
}
# 2. 管理后臺(tái)
server {
    listen 443 ssl;
    server_name admin.yourcompany.com;
    ssl_certificate /etc/ssl/certs/admin.crt;
    ssl_certificate_key /etc/ssl/private/admin.key;
    location / {
        proxy_pass http://admin-backend:9090;
        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;
    }
}
# 3. 靜態(tài)資源(可緩存)
server {
    listen 443 ssl;
    server_name static.yourcompany.com;
    ssl_certificate /etc/ssl/certs/static.crt;
    ssl_certificate_key /etc/ssl/private/static.key;
    location / {
        root /var/www/static;
        add_header Cache-Control "public, max-age=31536000";
        add_header Access-Control-Allow-Origin "*";
    }
}

你可以在 https://httpbin.org/headers 測(cè)試你的請(qǐng)求頭是否正確傳遞。只需用瀏覽器訪問(wèn)該鏈接,它會(huì)返回你發(fā)送的所有 HTTP 頭信息,包括 Host、X-Forwarded-* 等。

2.2 通配符域名與子域名泛解析

假設(shè)你的系統(tǒng)支持多租戶,每個(gè)租戶都有獨(dú)立子域名:

  • tenant1.yourcompany.com
  • tenant2.yourcompany.com
  • *.yourcompany.com

Nginx 支持正則表達(dá)式和通配符:

server {
    listen 443 ssl;
    server_name ~^(?<tenant>.+)\.yourcompany\.com$;
    ssl_certificate /etc/ssl/certs/wildcard.crt;
    ssl_certificate_key /etc/ssl/private/wildcard.key;
    # 從域名中提取租戶 ID,傳遞給后端
    set $tenant_id $tenant;
    location / {
        proxy_pass http://tenant-service:8080;
        proxy_set_header X-Tenant-ID $tenant_id;  # 自定義頭,后端可讀取
        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;
    }
}

在 Java 中,你可以這樣獲取租戶 ID:

@GetMapping("/dashboard")
public ResponseEntity<Map<String, Object>> getDashboard(
        HttpServletRequest request) {
    String tenantId = request.getHeader("X-Tenant-ID");
    if (tenantId == null || tenantId.isEmpty()) {
        return ResponseEntity.status(403).body(Map.of("error", "Tenant ID required"));
    }
    // 根據(jù) tenantId 查詢數(shù)據(jù)庫(kù),返回租戶專屬數(shù)據(jù)
    DashboardData data = dashboardService.findByTenant(tenantId);
    return ResponseEntity.ok(data.toMap());
}

這種模式廣泛用于 SaaS 平臺(tái),如 Notion、Airtable、Salesforce 的多租戶架構(gòu)。無(wú)需為每個(gè)租戶部署獨(dú)立服務(wù),一個(gè)后端實(shí)例即可處理所有子域名請(qǐng)求。

2.3 域名重定向:從 HTTP 到 HTTPS,從舊域到新域

你可能需要將舊域名遷移到新域名,或強(qiáng)制所有流量走 HTTPS:

# 強(qiáng)制 HTTP 跳轉(zhuǎn)到 HTTPS
server {
    listen 80;
    server_name api.yourcompany.com www.api.yourcompany.com;
    return 301 https://$host$request_uri;
}
# 舊域名重定向到新域名
server {
    listen 443 ssl;
    server_name legacy.yourcompany.com;
    ssl_certificate /etc/ssl/certs/legacy.crt;
    ssl_certificate_key /etc/ssl/private/legacy.key;
    location / {
        return 301 https://api.yourcompany.com$request_uri;
    }
}

return 301 是永久重定向,搜索引擎會(huì)更新索引,瀏覽器也會(huì)緩存該跳轉(zhuǎn),提升 SEO 和用戶體驗(yàn)。

三、路徑重寫:讓后端“看不見(jiàn)”前端路徑

路徑重寫(Rewrite)是 Nginx 最強(qiáng)大的功能之一。它允許你在請(qǐng)求被轉(zhuǎn)發(fā)前,動(dòng)態(tài)修改請(qǐng)求的 URI,而用戶和瀏覽器對(duì)此完全無(wú)感知。

3.1 使用 rewrite 指令:基礎(chǔ)語(yǔ)法

rewrite regex replacement [flag];
  • regex:正則表達(dá)式,匹配請(qǐng)求路徑
  • replacement:替換后的路徑
  • flag:可選標(biāo)志,如 last、break、redirect、permanent

示例 1:重寫/old-api/xxx→/new-api/xxx

location /old-api/ {
    rewrite ^/old-api/(.*)$ /new-api/$1 last;
    proxy_pass http://backend:8080;
}

請(qǐng)求:/old-api/v1/users/123
→ 被重寫為:/new-api/v1/users/123
→ 轉(zhuǎn)發(fā)到:http://backend:8080/new-api/v1/users/123

注意:rewrite 發(fā)生在 proxy_pass 之前!所以 proxy_pass 只需指向后端的根路徑即可。

示例 2:移除 URL 中的版本號(hào)(兼容舊客戶端)

location ~ ^/v[0-9]+/api/ {
    rewrite ^/v[0-9]+/(api/.*)$ /$1 last;
    proxy_pass http://backend:8080;
}

請(qǐng)求:/v1/api/users/api/users
請(qǐng)求:/v2/api/orders/api/orders

這個(gè)技巧在 API 版本遷移中極為實(shí)用。你可以在新版本中逐步淘汰 /v1/,而無(wú)需強(qiáng)制所有客戶端升級(jí)。

3.2 使用 location + proxy_pass 實(shí)現(xiàn)更優(yōu)雅的重寫

有時(shí),rewrite 不是最佳選擇。更推薦使用 location 的正則匹配 + proxy_pass 帶路徑的組合。

location ~ ^/v[0-9]+/api/(.*)$ {
    proxy_pass http://backend:8080/api/$1;
    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;
}

這個(gè)寫法更清晰、更高效,因?yàn)椋?/p>

  • Nginx 在 location 匹配階段就捕獲了路徑參數(shù)((.*)
  • proxy_pass 直接拼接,無(wú)需額外的 rewrite 指令
  • 避免了 rewrite 的額外處理開銷

性能對(duì)比:在高并發(fā)場(chǎng)景下,location + proxy_passrewrite 快 15%-20%,因?yàn)闇p少了正則引擎的二次匹配。

3.3 實(shí)戰(zhàn)案例:將前端 SPA 路由轉(zhuǎn)發(fā)到后端 API

假設(shè)你有一個(gè) Vue.js 前端部署在 https://app.yourcompany.com,后端 API 部署在 https://api.yourcompany.com。但你希望用戶只記住一個(gè)域名:https://app.yourcompany.com。

于是你這樣配置:

server {
    listen 443 ssl;
    server_name app.yourcompany.com;
    ssl_certificate /etc/ssl/certs/app.crt;
    ssl_certificate_key /etc/ssl/private/app.key;
    # 靜態(tài)資源:前端打包文件
    location / {
        root /var/www/frontend;
        try_files $uri $uri/ /index.html;
    }
    # API 路徑重寫:所有 /api/* 轉(zhuǎn)發(fā)到后端
    location /api/ {
        proxy_pass http://backend:8080/;
        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;
    }
}

前端代碼中,你只需寫:

// Vue.js / React 請(qǐng)求
axios.get('/api/users'); // 實(shí)際請(qǐng)求的是 https://app.yourcompany.com/api/users
// 但 Nginx 會(huì)把它轉(zhuǎn)成 http://backend:8080/api/users

無(wú)需跨域配置!無(wú)需 CORS!前端和后端“看起來(lái)”在同一個(gè)域下,完美解決同源策略問(wèn)題!

3.4 復(fù)雜路徑重寫:多級(jí)路徑映射

想象一個(gè)復(fù)雜的微服務(wù)架構(gòu):

用戶請(qǐng)求路徑實(shí)際后端服務(wù)說(shuō)明
/v1/user/profileuser-service:8080/api/v1/profile用戶服務(wù)
/v1/order/listorder-service:8080/api/v1/orders訂單服務(wù)
/v1/payment/notifypayment-service:8080/webhook/v1/notify支付回調(diào)

你可以用多個(gè) location 實(shí)現(xiàn)精準(zhǔn)路由:

server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;
    # 用戶服務(wù)
    location ~ ^/v1/user/(.*)$ {
        proxy_pass http://user-service:8080/api/v1/$1;
        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;
    }
    # 訂單服務(wù)
    location ~ ^/v1/order/(.*)$ {
        proxy_pass http://order-service:8080/api/v1/$1;
        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;
    }
    # 支付服務(wù)(特殊路徑)
    location ~ ^/v1/payment/notify$ {
        proxy_pass http://payment-service:8080/webhook/v1/notify;
        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;
    }
    # 默認(rèn)兜底:404
    location / {
        return 404;
    }
}

每個(gè)服務(wù)都有獨(dú)立的路徑空間,互不干擾,易于維護(hù)。后端服務(wù)無(wú)需關(guān)心“全局路徑前綴”,只專注自己的業(yè)務(wù)路徑。

四、高級(jí)技巧:條件路由、負(fù)載均衡與動(dòng)態(tài)代理

Nginx 的強(qiáng)大遠(yuǎn)不止靜態(tài)配置。它支持基于請(qǐng)求頭、Cookie、IP、變量的條件判斷,實(shí)現(xiàn)智能路由。

4.1 基于 User-Agent 的路由(移動(dòng)端 vs PC)

map $http_user_agent $backend {
    default "mobile-backend";
    ~*"(Chrome|Firefox|Safari|Edge)" "web-backend";
}
server {
    listen 443 ssl;
    server_name app.yourcompany.com;
    location / {
        proxy_pass http://$backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  • 如果 User-Agent 包含 Chrome/Firefox → 轉(zhuǎn)發(fā)到 web-backend
  • 否則(如手機(jī)瀏覽器)→ 轉(zhuǎn)發(fā)到 mobile-backend

你可以為移動(dòng)端部署輕量版 API,減少 JSON 字段、關(guān)閉日志、啟用壓縮,提升體驗(yàn)。

4.2 基于 Cookie 的灰度發(fā)布(A/B 測(cè)試)

假設(shè)你正在發(fā)布新版本的用戶服務(wù),想讓 10% 的用戶訪問(wèn)新版。

map $cookie_gateway_version $upstream {
    default "backend-v1";
    "v2" "backend-v2";
}
server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    location /api/v1/user {
        proxy_pass http://$upstream/api/v1/user;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

然后在前端代碼中,隨機(jī)設(shè)置 Cookie:

// 在用戶登錄后隨機(jī)設(shè)置
if (Math.random() < 0.1) {
    document.cookie = "gateway_version=v2; path=/; max-age=3600";
}

這種方式無(wú)需修改 Nginx 配置,僅通過(guò)前端控制 Cookie,即可實(shí)現(xiàn)無(wú)感知灰度發(fā)布。適用于金融、電商等高敏感場(chǎng)景。

4.3 負(fù)載均衡:多實(shí)例自動(dòng)分發(fā)

upstream user-service {
    server 10.0.0.10:8080 weight=3;
    server 10.0.0.11:8080 weight=1;
    server 10.0.0.12:8080 backup;  # 備用節(jié)點(diǎn)
}
server {
    listen 443 ssl;
    server_name api.yourcompany.com;
    location /api/v1/user {
        proxy_pass http://user-service;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
  • weight=3:每 4 個(gè)請(qǐng)求,3 個(gè)發(fā)給 10.0.0.10,1 個(gè)發(fā)給 10.0.0.11
  • backup:只有當(dāng)主節(jié)點(diǎn)全掛時(shí)才啟用

?? Nginx 支持多種負(fù)載均衡算法:round-robin(默認(rèn))、least_conn(最少連接)、ip_hash(會(huì)話保持)

upstream user-service {
    ip_hash;  # 同一 IP 的請(qǐng)求總是發(fā)給同一臺(tái)后端
    server 10.0.0.10:8080;
    server 10.0.0.11:8080;
}

ip_hash 適用于需要會(huì)話保持的場(chǎng)景(如購(gòu)物車、登錄態(tài)),但犧牲了負(fù)載均衡的均勻性。

4.4 動(dòng)態(tài)上游:結(jié)合 Lua 或外部服務(wù)(進(jìn)階)

雖然 Nginx 本身不支持動(dòng)態(tài) DNS 查詢,但可通過(guò) ngx_http_lua_module 實(shí)現(xiàn):

location /dynamic-api {
    content_by_lua_block {
        local res = ngx.location.capture("/resolve-backend")
        local backend = res.body
        ngx.req.set_uri("/api/v1/user", false)
        ngx.var.upstream = backend
        ngx.exec("/proxy-to-backend")
    }
}

這需要 OpenResty 環(huán)境,適合高階用戶。普通場(chǎng)景建議使用 Consul + nginx-upsync-module 實(shí)現(xiàn)動(dòng)態(tài)上游更新。

五、Java 后端實(shí)戰(zhàn):如何配合 Nginx 構(gòu)建現(xiàn)代化網(wǎng)關(guān)

現(xiàn)在,我們來(lái)構(gòu)建一個(gè)完整的 Java 微服務(wù) + Nginx 反向代理系統(tǒng)。

5.1 后端服務(wù):Spring Boot API

package com.example.gatewaydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
@RestController
public class GatewayDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayDemoApplication.class, args);
    }
    @GetMapping("/api/v1/user")
    public Map<String, Object> getUserInfo(
            HttpServletRequest request,
            @RequestHeader(value = "X-Tenant-ID", required = false) String tenantId) {
        Map<String, Object> response = new HashMap<>();
        response.put("status", "success");
        response.put("message", "Hello from Java backend!");
        response.put("requestedPath", request.getRequestURI());
        response.put("clientIp", request.getHeader("X-Real-IP"));
        response.put("originalHost", request.getHeader("Host"));
        response.put("tenantId", tenantId);
        response.put("protocol", request.getHeader("X-Forwarded-Proto"));
        return response;
    }
    @GetMapping("/api/v1/health")
    public Map<String, String> health() {
        Map<String, String> health = new HashMap<>();
        health.put("status", "UP");
        health.put("version", "1.2.3");
        return health;
    }
}

啟動(dòng)后,訪問(wèn) http://localhost:8080/api/v1/user,你會(huì)看到:

{
  "status": "success",
  "message": "Hello from Java backend!",
  "requestedPath": "/api/v1/user",
  "clientIp": "127.0.0.1",
  "originalHost": "localhost:8080",
  "tenantId": null,
  "protocol": "http"
}

5.2 Nginx 配置:統(tǒng)一入口 + 路徑重寫 + 多域名

# 定義上游組
upstream java-backend {
    server 127.0.0.1:8080;
}
server {
    listen 443 ssl;
    server_name api.example.com www.api.example.com;
    ssl_certificate /etc/ssl/certs/api.crt;
    ssl_certificate_key /etc/ssl/private/api.key;
    # 所有 /api/v1/* 請(qǐng)求轉(zhuǎn)發(fā)到后端
    location ~ ^/api/v1/(.*)$ {
        proxy_pass http://java-backend/api/v1/$1;
        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;
        # 添加安全頭
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options DENY;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    }
    # 健康檢查端點(diǎn)(不經(jīng)過(guò)重寫)
    location /health {
        proxy_pass http://java-backend/health;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    # 默認(rèn)響應(yīng)
    location / {
        return 404 "Not Found. Use /api/v1/* endpoints.";
    }
}
# 管理后臺(tái)
server {
    listen 443 ssl;
    server_name admin.example.com;
    ssl_certificate /etc/ssl/certs/admin.crt;
    ssl_certificate_key /etc/ssl/private/admin.key;
    location / {
        proxy_pass http://java-backend;
        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;
    }
}
# 強(qiáng)制 HTTPS
server {
    listen 80;
    server_name api.example.com www.api.example.com admin.example.com;
    return 301 https://$host$request_uri;
}

5.3 測(cè)試驗(yàn)證

  1. 啟動(dòng) Java 服務(wù):java -jar gateway-demo.jar
  2. 訪問(wèn):https://api.example.com/api/v1/user

你會(huì)看到響應(yīng):

{
  "status": "success",
  "message": "Hello from Java backend!",
  "requestedPath": "/api/v1/user",
  "clientIp": "192.168.1.100",
  "originalHost": "api.example.com",
  "tenantId": null,
  "protocol": "https"
}

? 注意:originalHostapi.example.com,而非 localhost:8080,說(shuō)明 Nginx 成功傳遞了原始域名。

  1. 訪問(wèn):https://admin.example.com/api/v1/user

你會(huì)看到:404 —— 因?yàn)楹蠖朔?wù)沒(méi)有 /api/v1/user 路徑(它只在 api.example.com 下暴露)

這正是我們想要的:不同域名暴露不同 API,實(shí)現(xiàn)邏輯隔離!

六、性能優(yōu)化與安全加固:生產(chǎn)環(huán)境必看

6.1 緩存靜態(tài)內(nèi)容

location ~* \.(jpg|jpeg|png|gif|ico|css|js|json|woff|woff2)$ {
    root /var/www/static;
    expires 1y;
    add_header Cache-Control "public, immutable";
    add_header Access-Control-Allow-Origin "*";
}

減少后端壓力,提升前端加載速度。

6.2 限制請(qǐng)求速率(防刷)

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
    location /api/v1/user {
        limit_req zone=api_limit burst=20 nodelay;
        proxy_pass http://java-backend;
        ...
    }
}
  • 每秒最多 10 個(gè)請(qǐng)求
  • 允許突發(fā) 20 個(gè)(burst)
  • nodelay:不延遲,直接拒絕超出部分

6.3 防止惡意請(qǐng)求頭

if ($http_user_agent ~* "sqlmap|nmap|nikto") {
    return 403;
}
if ($http_referer ~* "(spam|porn|gambling)") {
    return 403;
}

可結(jié)合 nginx-module-vtsModSecurity 做更深度的 WAF 防護(hù)。

6.4 啟用 Gzip 壓縮

gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

通??蓽p少 70% 的響應(yīng)體積,尤其對(duì) JSON API 效果顯著。

七、故障排查與日志分析

7.1 查看 Nginx 配置是否正確

nginx -t

輸出 syntax is oktest is successful 才能重啟。

7.2 實(shí)時(shí)查看訪問(wèn)日志

tail -f /var/log/nginx/access.log

典型日志格式:

192.168.1.10 - - [15/Apr/2024:10:23:45 +0800] "GET /api/v1/user HTTP/1.1" 200 1234 "-" "Mozilla/5.0"

7.3 自定義日志格式(記錄更多上下文)

log_format detailed '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time" '
                    'host="$host" x-forwarded-for="$http_x_forwarded_for"';
access_log /var/log/nginx/access.log detailed;

日志中將包含:

  • 請(qǐng)求耗時(shí)(request_time
  • 上游連接時(shí)間(upstream_connect_time
  • 上游響應(yīng)頭時(shí)間(upstream_header_time
  • 上游響應(yīng)體時(shí)間(upstream_response_time

一旦后端慢,你就能立即判斷是網(wǎng)絡(luò)問(wèn)題、后端處理慢,還是數(shù)據(jù)庫(kù)慢!

八、架構(gòu)演進(jìn):從 Nginx 到服務(wù)網(wǎng)格

隨著微服務(wù)規(guī)模擴(kuò)大,Nginx 的配置會(huì)變得復(fù)雜難維護(hù)。此時(shí),你可以考慮:

方案適用場(chǎng)景優(yōu)勢(shì)劣勢(shì)
Nginx小中型系統(tǒng),單一入口配置簡(jiǎn)單、性能極高、資源消耗低無(wú)服務(wù)發(fā)現(xiàn)、無(wú)熔斷、無(wú)追蹤
Spring Cloud GatewayJava 技術(shù)棧統(tǒng)一深度集成 Spring 生態(tài)、支持?jǐn)嗦菲?、重?/td>JVM 開銷大、不適合靜態(tài)資源
Envoy / Istio大型云原生系統(tǒng)服務(wù)網(wǎng)格、mTLS、流量鏡像、金絲雀發(fā)布學(xué)習(xí)曲線陡峭、運(yùn)維復(fù)雜

建議路徑
小團(tuán)隊(duì) → Nginx 精細(xì)化配置
中型團(tuán)隊(duì) → Nginx + Prometheus + Grafana 監(jiān)控
大型團(tuán)隊(duì) → Istio + K8s + Linkerd

九、總結(jié):你掌握的,不只是配置,是架構(gòu)話語(yǔ)權(quán)

通過(guò)本文,你已經(jīng)掌握了:

? Nginx 反向代理的核心原理
? 域名轉(zhuǎn)發(fā)的多租戶實(shí)現(xiàn)
? 路徑重寫的四種優(yōu)雅寫法
? Java 后端如何感知真實(shí)請(qǐng)求
? 負(fù)載均衡、灰度發(fā)布、限流、安全頭
? 生產(chǎn)環(huán)境最佳實(shí)踐與故障排查

更重要的是,你理解了:

Nginx 不是“轉(zhuǎn)發(fā)工具”,它是你的“流量指揮官”
它讓你能在不改動(dòng)一行后端代碼的前提下,完成:

  • 多域名隔離
  • API 版本平滑遷移
  • 租戶路由
  • 灰度發(fā)布
  • 安全加固
  • 性能優(yōu)化

這,就是架構(gòu)師的底氣。

十、延伸思考:如果你是 CTO,你會(huì)怎么設(shè)計(jì)?

想象你負(fù)責(zé)一個(gè)年交易額 10 億的電商平臺(tái),有:

  • 10 個(gè)微服務(wù)(用戶、商品、訂單、支付、庫(kù)存、推薦、風(fēng)控、物流、通知、后臺(tái))
  • 3 個(gè)前端(Web、App、小程序)
  • 5 個(gè)地域數(shù)據(jù)中心
  • 每天 5000 萬(wàn)次 API 調(diào)用

你會(huì)如何設(shè)計(jì) Nginx 層?

建議架構(gòu):

[全球用戶]
     ↓
[CDN 緩存靜態(tài)資源]
     ↓
[邊緣 Nginx(全球 10 節(jié)點(diǎn))]
     ↓
[區(qū)域 Nginx(北京/上海/廣州)]
     ↓
[服務(wù)網(wǎng)關(guān)(Spring Cloud Gateway)]
     ↓
[微服務(wù)集群(K8s)]
  • CDN:緩存圖片、CSS、JS
  • 邊緣 Nginx:做 DDOS 防護(hù)、IP 黑名單、SSL 終止
  • 區(qū)域 Nginx:做地域路由(如華北用戶走華北機(jī)房)
  • 網(wǎng)關(guān):做鑒權(quán)、限流、日志、熔斷
  • 微服務(wù):專注業(yè)務(wù)邏輯

Nginx 在這里,是流量的過(guò)濾器、加速器、調(diào)度器,不是簡(jiǎn)單的代理。

結(jié)語(yǔ):讓配置成為藝術(shù)

配置文件不是冰冷的文本,它是你系統(tǒng)架構(gòu)的藍(lán)圖,是你與流量對(duì)話的語(yǔ)言。

當(dāng)你能用一行 proxy_pass,讓千萬(wàn)用戶無(wú)感知地切換后端服務(wù);
當(dāng)你能用一個(gè) rewrite,讓舊系統(tǒng)優(yōu)雅退場(chǎng);
當(dāng)你能用一個(gè) map,讓 A/B 測(cè)試毫秒級(jí)生效——

你,就不再是“寫代碼的人”,而是系統(tǒng)架構(gòu)的設(shè)計(jì)師

Nginx 的力量,不在于它能做什么,而在于它讓你不用做什么。
你無(wú)需改 Java 代碼,無(wú)需重啟服務(wù),無(wú)需發(fā)布新版本,就能完成一次全局流量重構(gòu)。

這就是反向代理的終極魅力。

附錄:常用 Nginx 指令速查表

指令用途
proxy_pass轉(zhuǎn)發(fā)請(qǐng)求到后端
proxy_set_header設(shè)置轉(zhuǎn)發(fā)頭
rewrite重寫 URI
location匹配請(qǐng)求路徑
upstream定義后端集群
limit_req限流
gzip啟用壓縮
expires設(shè)置緩存
return返回 HTTP 狀態(tài)碼
map變量映射(強(qiáng)大?。?/td>
try_files優(yōu)先查找本地文件

以上就是Nginx反向代理之域名轉(zhuǎn)發(fā)與路徑重寫配置指南的詳細(xì)內(nèi)容,更多關(guān)于Nginx域名轉(zhuǎn)發(fā)與路徑重寫配置的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用LDAP實(shí)現(xiàn)Nginx用戶認(rèn)證的示例

    使用LDAP實(shí)現(xiàn)Nginx用戶認(rèn)證的示例

    本文主要使用Nginx和LDAP實(shí)現(xiàn)用戶認(rèn)證,通過(guò)配置Nginx和安裝nginx-auth-ldap模塊,可以實(shí)現(xiàn)基于LDAP的認(rèn)證邏輯,下面就來(lái)介紹一下,感興趣的可以了解一下
    2024-12-12
  • 前端項(xiàng)目中Nginx配置指南詳解

    前端項(xiàng)目中Nginx配置指南詳解

    這篇文章主要為大家詳細(xì)介紹了在前端項(xiàng)目開發(fā)中如何配置Nginx,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下
    2023-09-09
  • Linux下Nginx安裝教程

    Linux下Nginx安裝教程

    這篇文章主要為大家詳細(xì)介紹了Linux中Nginx的安裝教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • Forever+nginx部署Node站點(diǎn)的方法示例

    Forever+nginx部署Node站點(diǎn)的方法示例

    這篇文章主要介紹了Forever+nginx部署Node站點(diǎn)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • nginx+lua+redis 灰度發(fā)布實(shí)現(xiàn)方案

    nginx+lua+redis 灰度發(fā)布實(shí)現(xiàn)方案

    在微服務(wù)化進(jìn)程中,利用nginx+lua+redis實(shí)現(xiàn)灰度發(fā)布至關(guān)重要,,通過(guò)nginx+lua反向代理,根據(jù)客戶端ip進(jìn)行路由控制,配合redis存儲(chǔ)允許訪問(wèn)微服務(wù)的ip地址,可以有效地進(jìn)行用戶分流,感興趣的可以了解一下
    2024-10-10
  • Nginx 上傳大文件超時(shí)解決辦法

    Nginx 上傳大文件超時(shí)解決辦法

    這篇文章主要介紹了Nginx 上傳大文件超時(shí)解決辦法的相關(guān)資料,這里上傳文件并設(shè)置nginx的配置文件防止超時(shí)的情況,需要的朋友可以參考下
    2017-07-07
  • 通過(guò)配置nginx訪問(wèn)服務(wù)器靜態(tài)資源的過(guò)程

    通過(guò)配置nginx訪問(wèn)服務(wù)器靜態(tài)資源的過(guò)程

    文章介紹了圖片存儲(chǔ)路徑設(shè)置、Nginx服務(wù)器配置及通過(guò)http://192.168.206.170:8007/a.png訪問(wèn)圖片的方法,涵蓋圖片管理與服務(wù)部署的核心步驟
    2025-08-08
  • nginx封空user_agent實(shí)現(xiàn)封禁迅雷的方法

    nginx封空user_agent實(shí)現(xiàn)封禁迅雷的方法

    nginx封空user_agent實(shí)現(xiàn)封禁迅雷的方法,需要的朋友可以參考下。
    2010-11-11
  • nginx訪問(wèn)控制的實(shí)現(xiàn)示例

    nginx訪問(wèn)控制的實(shí)現(xiàn)示例

    這篇文章主要介紹了nginx訪問(wèn)控制的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • nginx處理http請(qǐng)求實(shí)例詳解

    nginx處理http請(qǐng)求實(shí)例詳解

    這篇文章主要介紹了nginx處理http請(qǐng)求實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06

最新評(píng)論

大化| 沙河市| 德格县| 池州市| 潍坊市| 安徽省| 丹巴县| 平潭县| 龙游县| 莱西市| 嘉定区| 延吉市| 青龙| 汽车| 临泉县| 汉沽区| 绍兴县| 农安县| 松潘县| 梨树县| 准格尔旗| 登封市| 闸北区| 太和县| 定安县| 吉水县| 全南县| 溧水县| 镇坪县| 襄樊市| 墨竹工卡县| 商都县| 五峰| 二手房| 东海县| 铁岭市| 浙江省| 大荔县| 博乐市| 华宁县| 余庆县|