在调用 API 时使用 nginx 作为反向代理时,从 nginx 获取 502 Bad Gateway

问题描述 投票:0回答:1

我一直在尝试使用 nginx 作为我的外部 REST GET API 之一的反向代理来调试我的 golang 服务和外部服务之间的延迟问题。

我可以轻松地通过golang的net/http库调用该公共URL并获得成功的响应,但是当我使用nginx作为反向代理时,nginx给出了502 Bad Gateway。在 nginx-error.log 文件中,我收到有关 SSL 的错误,如下所示,但想知道如何在通过 golang net/http 客户端调用该 API 时不会收到错误。

P.S:我通过创建一个简单的 /ping-nginx API 来交叉检查 nginx 是否正在运行,该 API 仅返回 200 statusCode 和 pong-nginx 作为响应。

ping.go

package main

import (
    "fmt"
    "log"
    "net/http"
    "strconv"
)

func main() {
    http.HandleFunc("/ping-via-go-client", func(w http.ResponseWriter, r *http.Request) {
        url := "https://flights-explorer.makemytrip.com/ping"
        resp, err := http.Get(url)
        var statusCode string
        if err == nil {
            statusCode = strconv.Itoa(resp.StatusCode)
        }
        fmt.Fprintf(w, "pong-via-go-client with statusCode:"+statusCode)
    })

    http.HandleFunc("/ping-via-nginx", func(w http.ResponseWriter, r *http.Request) {
        url := "http://localhost/ping"
        resp, err := http.Get(url)
        var statusCode string
        if err == nil {
            statusCode = strconv.Itoa(resp.StatusCode)
        }
        fmt.Fprintf(w, "pong-via-nginx with statusCode:"+statusCode)
    })

    log.Fatal(http.ListenAndServe(":3003", nil))
}

卷发的反应:

➜  ~ curl http://localhost:3003/ping-via-go-client
pong-via-go-client with statusCode:200%
➜  ~ curl http://localhost:3003/ping-via-nginx
pong-via-nginx with statusCode:502%

nginx.conf

#user  nginx;
daemon off;

worker_processes  auto;

error_log  /opt/logs/nginx-error.log warn;
pid        /var/run/nginx.pid;
events {
    worker_connections  250;
}
http {
log_format upstream_time '$time_local $status $remote_addr to:- $upstream_addr $request '
    'uct:$upstream_connect_time uht:$upstream_header_time urt:$upstream_response_time '
    'request_time:$request_time tid_header:$http_tid status:$upstream_cache_status '
    'slot:$http_slot slot_time:$http_slotstarttime ttl_req:$http_ttl ttl_resp:$upstream_http_x_accel_expires '
    'job_flag:$http_jobflag cookies:"$http_cookie" bytes_sent:$bytes_sent gzip_ratio:$gzip_ratio '
    '"$http_referer" "$http_user_agent" $http_x_forwarded_for cur_time:$msec';
        keepalive_timeout 85;
        upstream flights-explorer.makemytrip.com {
              server flights-explorer.makemytrip.com:443;
              keepalive 30;
        }
    server {
        listen 80;
        access_log /opt/logs/nginx-access.log upstream_time;
                  location = /basic_status {
                            stub_status;
                  }

        location /ping-nginx {
            return 200 'pong-nginx\n';
            add_header Content-Type text/plain;
        }

        location /ping {
               # proxy_buffering off;
             proxy_pass https://flights-explorer.makemytrip.com$request_uri;
             proxy_http_version 1.1;
             proxy_set_header Connection "";
             proxy_ssl_verify off;  # Disable SSL certificate verification
             proxy_ssl_verify_depth 0;
             #proxy_ssl_session_reuse on;
             #proxy_socket_keepalive on;
             proxy_connect_timeout 10s;
             proxy_read_timeout 10s;
        }

    }
}

nginx-error.log 中的错误

2024/03/03 11:07:55 [error] 20078#0: *6 SSL_do_handshake() failed (SSL: error:0A000438:SSL routines::tlsv1 alert internal error:SSL alert number 80) while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET /ping HTTP/1.1", upstream: "https://23.63.110.25:443/ping", host: "localhost"
2024/03/03 11:07:55 [warn] 20078#0: *6 upstream server temporarily disabled while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET /ping HTTP/1.1", upstream: "https://23.63.110.25:443/ping", host: "localhost"
2024/03/03 11:07:55 [error] 20078#0: *6 SSL_do_handshake() failed (SSL: error:0A000438:SSL routines::tlsv1 alert internal error:SSL alert number 80) while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET /ping HTTP/1.1", upstream: "https://23.63.110.67:443/ping", host: "localhost"
2024/03/03 11:07:55 [warn] 20078#0: *6 upstream server temporarily disabled while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET /ping HTTP/1.1", upstream: "https://23.63.110.67:443/ping", host: "localhost"
2024/03/03 11:07:56 [error] 20078#0: *6 SSL_do_handshake() failed (SSL: error:0A000438:SSL routines::tlsv1 alert internal error:SSL alert number 80) while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET /ping HTTP/1.1", upstream: "https://23.63.110.74:443/ping", host: "localhost"
2024/03/03 11:07:56 [warn] 20078#0: *6 upstream server temporarily disabled while SSL handshaking to upstream, client: 127.0.0.1, server: , request: "GET /ping HTTP/1.1", upstream: "https://23.63.110.74:443/ping", host: "localhost"

日志位于 nginx-access.log

03/Mar/2024:11:07:56 +0530 502 127.0.0.1 to:- 23.63.110.25:443, 23.63.110.67:443, 23.63.110.74:443 GET /ping HTTP/1.1 uct:-, -, - uht:-, -, - urt:0.131, 0.116, 0.107 request_time:0.354 tid_header:- status:- slot:- slot_time:- ttl_req:- ttl_resp:- job_flag:- cookies:"-" bytes_sent:314 gzip_ratio:- "-" "Go-http-client/1.1" - cur_time:1709444276.083
go nginx ssl nginx-reverse-proxy
1个回答
0
投票

从评论中,你可以尝试:

http {
    upstream backend {
        server flights-explorer.makemytrip.com:443;
        keepalive 30;
    }

    server {
        listen 80;
        
        location /ping {
            proxy_pass https://backend;
            proxy_http_version 1.1;
            proxy_set_header Connection "";
            proxy_ssl_verify off;
            proxy_ssl_server_name on;
            proxy_set_header Host $host;
            proxy_connect_timeout 10s;
            proxy_read_timeout 10s;
            proxy_ssl_name $host;
        }

        location /ping-nginx {
            return 200 'pong-nginx\n';
            add_header Content-Type text/plain;
        }
    }
}
  • proxy_ssl_server_name on;
    指令启用SNI支持,允许Nginx向上游服务器提供正确的虚拟主机。这反映了 Go
    http.Client
    默认情况下的操作。

  • proxy_set_header Host $host;
    确保传递到上游的 Host 标头与原始请求匹配,上游服务器可能需要这样做才能正确处理请求。

  • proxy_ssl_verify off;
    仅对调试有用。出于安全目的,您必须在生产环境中启用它:它会绕过 SSL 证书验证,类似于如果未明确强制执行证书验证,Go 客户端中可能会发生的情况。

尽管评论提到 API 应该以 <1ms, network conditions or server processing times might still cause delays. Adjusting

proxy_connect_timeout
proxy_read_timeout
适当地响应,但再次可以为调试目的提供帮助。
并通过设置
error_log /path/to/error.log debug;
增强 Nginx 的日志记录以获得更详细的调试信息。

Go

http.Client
自动处理 HTTP 和 SSL 通信的许多方面,包括 SNI 和主机标头。默认 Go 客户端对 SSL、标头或
keep-alives
的处理方式可能与上游服务器的期望更兼容。
您可以比较 Go(使用 Wireshark
tcpdump
等网络嗅探工具来捕获从 Go 客户端到服务器的流量)和 Nginx(通过调试日志)生成的实际请求标头和 SSL 握手详细信息,以发现差异。

© www.soinside.com 2019 - 2024. All rights reserved.