Nginx捕获上游服务器响应头配置、文档及转发需求咨询
Hey there! Let's tackle your two Nginx questions step by step—these are really common scenarios, so I’ve got clear, actionable solutions for you.
Capturing upstream response headers in Nginx can serve two main purposes: logging them for debugging/analytics, or using them to drive internal logic (like modifying the response sent to clients). Here’s how to do both:
1. Log upstream response headers to Nginx logs
Define a custom log format that includes the upstream headers you care about, then attach it to your server or location block. Use the $upstream_http_ prefix followed by the lowercase header name (replace hyphens with underscores).
# Add this in the http block to define your custom log format log_format upstream_header_log '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'Upstream-X-Custom: "$upstream_http_x_custom_header" ' 'Upstream-Trace-ID: "$upstream_http_x_trace_id"'; # In your server or location block, enable the custom log server { listen 80; server_name your-domain.com; location / { proxy_pass http://your-upstream-server; access_log /var/log/nginx/upstream_headers.log upstream_header_log; } }
2. Use upstream response headers in Nginx logic
You can pass upstream headers to clients, or use them to make routing/modification decisions.
Example 1: Forward upstream headers to clients
location / { proxy_pass http://your-upstream-server; # Forward the upstream's X-Upstream-Data header to the client proxy_set_header X-Forwarded-Upstream-Data $upstream_http_x_upstream_data; # Or add a new header using the upstream value add_header X-Upstream-Trace $upstream_http_x_trace_id always; }
Example 2: Route based on upstream headers
location / { proxy_pass http://your-upstream-server; # Redirect clients if the upstream returns a specific header value if ($upstream_http_x_access_level = "admin") { return 302 /admin-dashboard; } }
Forwarding responses (or requests) to another upstream depends on your use case—whether you need real-time mirroring, conditional forwarding based on the first upstream’s response, or failover.
1. Real-time request mirroring (forward to two upstreams simultaneously)
Use Nginx’s mirror module to duplicate incoming requests and send them to a secondary upstream. This is great for syncing data across services or testing new backends.
http { upstream primary_backend { server 192.168.1.10:8080; } upstream secondary_backend { server 192.168.1.11:8080; } server { listen 80; server_name your-domain.com; location / { # Send main request to primary backend proxy_pass http://primary_backend; # Mirror the request to the secondary backend (ignore its response) mirror /mirror-endpoint; mirror_request_body on; # Include the request body in the mirror } # Internal-only location for mirroring (can't be accessed externally) location = /mirror-endpoint { internal; proxy_pass http://secondary_backend$request_uri; proxy_pass_request_body on; proxy_pass_request_headers on; } } }
2. Conditional forwarding based on first upstream’s response
If you need to fetch a response from the first upstream, then forward to a second based on that response’s content/headers, use OpenResty’s Lua module for flexibility.
http { upstream first_upstream { server 192.168.1.10:8080; } upstream second_upstream { server 192.168.1.11:8080; } server { listen 80; server_name your-domain.com; location / { content_by_lua_block { # First, fetch response from the primary upstream local primary_res = ngx.location.capture('/fetch-primary') # Check if we need to forward to the secondary upstream if primary_res.status == 200 and primary_res.headers['X-Forward-To-Secondary'] == 'true' then # Fetch response from secondary upstream local secondary_res = ngx.location.capture('/fetch-secondary') # Return the secondary upstream's response to the client ngx.status = secondary_res.status ngx.say(secondary_res.body) for header, value in pairs(secondary_res.headers) do ngx.header[header] = value end else # Return the primary upstream's response ngx.status = primary_res.status ngx.say(primary_res.body) for header, value in pairs(primary_res.headers) do ngx.header[header] = value end end } } # Internal locations to fetch from each upstream location = /fetch-primary { internal; proxy_pass http://first_upstream$request_uri; } location = /fetch-secondary { internal; proxy_pass http://second_upstream$request_uri; } } }
3. Failover: Forward to backup upstream on failure
If you want to automatically switch to a backup upstream when the primary one fails (returns errors/timeouts), use proxy_next_upstream:
upstream backend_cluster { server 192.168.1.10:8080; server 192.168.1.11:8080 backup; # Mark as backup } server { listen 80; server_name your-domain.com; location / { proxy_pass http://backend_cluster; # Trigger failover on errors, timeouts, or specific HTTP status codes proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; proxy_next_upstream_tries 2; # Try up to 2 times (primary + backup) } }
内容的提问来源于stack exchange,提问作者SocketM

