V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
gansteed
V2EX  ›  问与答

Nginx HTTP/2 over TLS 访问报 400,有熟悉的同学吗?

  •  
  •   gansteed · 2019-01-28 15:00:07 +08:00 · 3217 次点击
    这是一个创建于 2113 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在写一个 HTTP/2 的代理。如果是不带 TLS 的话,是可以正常工作的,

        server {
            listen 8443 http2;
    
            location / {
                error_log /Users/jiajun/nginx_error_log.log debug;
                grpc_pass grpc://127.0.0.1:2017;
            }
        }
    

    执行一下:

    $ go run example/grpc_client/main.go
    calling to 127.0.0.1:2019
    2019/01/28 11:50:46 gonna call c.SayHello...
    2019/01/28 11:50:46 Greeting: Hello world
    

    Nginx 日志是:

    127.0.0.1 - - [28/Jan/2019:11:50:46 +0800] "POST /helloworld.Greeter/SayHello HTTP/2.0" 200 18 "-" "grpc-go/1.16.0" "-"
    

    加证书之后:

        server {
            listen 8443 ssl http2;
            ssl_certificate     /Users/jiajun/127.0.0.1.crt;
            ssl_certificate_key /Users/jiajun/127.0.0.1.key;
    
            location / {
                error_log /Users/jiajun/nginx_error_log.log debug;
                grpc_pass grpc://127.0.0.1:2017;
            }
        }
    

    执行一下:

    $ go run example/grpc_client/main.go
    calling to 127.0.0.1:2019
    2019/01/28 11:53:06 gonna call c.SayHello...
    2019/01/28 11:53:06 could not greet: rpc error: code = Unavailable desc = transport is closing
    exit status 1
    

    Nginx 日志:

        127.0.0.1 - - [28/Jan/2019:11:53:06 +0800] "PRI * HTTP/2.0" 400 157 "-" "-" "-"
    

    有同学遇到同样的问题吗?

    此外,可以写一个简单的 demo 复现问题:

    package main
    
    import (
    	"crypto/tls"
    	"log"
    )
    
    func main() {
    	backendConn, err := tls.Dial("tcp", "127.0.0.1:8443", &tls.Config{InsecureSkipVerify: true})
    	if err != nil {
    		log.Printf("failed to dial: %s", err)
    	}
    
    	if _, err := backendConn.Write([]byte("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")); err != nil {
    		log.Printf("failed to write: %s", err)
    	}
    
    	b := make([]byte, 4096)
    	if _, err := backendConn.Read(b); err != nil {
    		log.Printf("failed to read: %s", err)
    	}
    
    	log.Printf("result: %s", b)
    }
    

    结果:

    $ go run main.go
    2019/01/28 14:59:50 result: HTTP/1.1 400 Bad Request
    Server: nginx/1.15.8
    Date: Mon, 28 Jan 2019 06:59:50 GMT
    Content-Type: text/html
    Content-Length: 157
    Connection: close
    
    <html>
    <head><title>400 Bad Request</title></head>
    <body>
    <center><h1>400 Bad Request</h1></center>
    <hr><center>nginx/1.15.8</center>
    </body>
    </html>
    
    第 1 条附言  ·  2019-01-30 10:19:45 +08:00
    是 ALPN 的问题,指定好协议就可以了:

    tls.Dial("tcp", backendAddr, &tls.Config{NextProtos: []string{"h2"}})
    3 条回复    2019-01-29 17:33:14 +08:00
    justfly
        1
    justfly  
       2019-01-28 15:24:01 +08:00
    很迷,你给的配置 nginx 监听的 8443 端口,log 里面却是连接 2019 端口。demo 里面去访问一个 http/2 服务,http/2 是二进制协议,你在 tls 连接上直接给的是纯文本协议。。。
    gansteed
        2
    gansteed  
    OP
       2019-01-28 16:32:01 +08:00
    popstk
        3
    popstk  
       2019-01-29 17:33:14 +08:00
    https://github.com/grpc/grpc-go#the-rpc-failed-with-error-code--unavailable-desc--transport-is-closing
    试试配下证书->
    <code>
    certificate, err := credentials.NewServerTLSFromFile(crtFile, keyFile)
    if err != nil {
    log.Fatalf("can not load certificate: %v", err)
    }
    conn, err := grpc.Dial(address, grpc.WithTransportCredentials(certificate))
    if err != nil {
    log.Fatalf("did not connect: %v", err)
    }
    </code>
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2720 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 11:43 · PVG 19:43 · LAX 03:43 · JFK 06:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.