https://nullget.sourceforge.io/?q=node/895
grpc與http2的關系
grpc client 發送包到原生的http2 server
client收到報錯:
panic: rpc error: code = 9 desc = transport: received the unexpected content-type "text/html; charset=UTF-8"
server端輸出:
輸出正常,包括了http2的所有信息,默認情況下響應了404。
[id=1] [ 3.994] send SETTINGS frame <length=6, flags=0x00, stream_id=0>
(niv=1)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[id=1] [ 3.994] recv SETTINGS frame <length=0, flags=0x00, stream_id=0>
(niv=0)
[id=1] [ 3.994] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=983025)
[id=1] [ 3.995] recv (stream_id=1) :method: POST
[id=1] [ 3.995] recv (stream_id=1) :scheme: http
[id=1] [ 3.995] recv (stream_id=1) :path: /flyrun.FlyRun/Run
[id=1] [ 3.995] recv (stream_id=1) :authority: 127.0.0.1
[id=1] [ 3.995] recv (stream_id=1) content-type: application/grpc
[id=1] [ 3.995] recv (stream_id=1) user-agent: grpc-go/1.0
[id=1] [ 3.995] recv (stream_id=1) te: trailers
[id=1] [ 3.995] recv HEADERS frame <length=62, flags=0x04, stream_id=1>
; END_HEADERS
(padlen=0)
; Open new stream
[id=1] [ 3.995] recv DATA frame <length=52, flags=0x01, stream_id=1>
; END_STREAM
[id=1] [ 3.995] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[id=1] [ 3.995] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[id=1] [ 3.995] send HEADERS frame <length=69, flags=0x04, stream_id=1>
; END_HEADERS
(padlen=0)
; First response header
:status: 404
server: nghttpd nghttp2/1.19.0
date: Fri, 10 Feb 2017 07:17:14 GMT
content-type: text/html; charset=UTF-8
content-length: 147
[id=1] [ 3.995] send DATA frame <length=147, flags=0x01, stream_id=1>
; END_STREAM
[id=1] [ 3.995] stream_id=1 closed
[id=1] [ 4.001] closed
總結:
原生http2協議server端能夠完全解析grpc客戶端發送的請求,獲取任意請求信息。 原生http2協議server默認響應不符合grpc客戶端標准。 從grpc客戶端的響應來看,應該是content-type不對。
grpc客戶端自定義的固定頭信息: content-type: application/grpc user-agent: grpc-go/1.0 method: POST
也就是說,grpc規定了一些固定的特定的頭信息的值,這是與原生http2協議不一樣的。
http2 client 發送包到 grpc server
grpc server收到的信息:
2017/02/10 15:46:58 transport: http2Server.HandleStreams found unhandled frame type [FrameHeader PRIORITY stream=3 len=5].
2017/02/10 15:46:58 transport: http2Server.HandleStreams found unhandled frame type [FrameHeader PRIORITY stream=5 len=5].
2017/02/10 15:46:58 transport: http2Server.HandleStreams found unhandled frame type [FrameHeader PRIORITY stream=7 len=5].
2017/02/10 15:46:58 transport: http2Server.HandleStreams found unhandled frame type [FrameHeader PRIORITY stream=9 len=5].
2017/02/10 15:46:58 transport: http2Server.HandleStreams found unhandled frame type [FrameHeader PRIORITY stream=11 len=5].
原生 http2 發送與接收的信息:
nghttp -v http://127.0.0.1:5000/abc/efg/hehe [15/412]
[ 0.000] Connected
[ 0.000] send SETTINGS frame <length=12, flags=0x00, stream_id=0>
(niv=2)
[SETTINGS_MAX_CONCURRENT_STREAMS(0x03):100]
[SETTINGS_INITIAL_WINDOW_SIZE(0x04):65535]
[ 0.000] send PRIORITY frame <length=5, flags=0x00, stream_id=3>
(dep_stream_id=0, weight=201, exclusive=0)
[ 0.000] send PRIORITY frame <length=5, flags=0x00, stream_id=5>
(dep_stream_id=0, weight=101, exclusive=0)
[ 0.000] send PRIORITY frame <length=5, flags=0x00, stream_id=7>
(dep_stream_id=0, weight=1, exclusive=0)
[ 0.000] send PRIORITY frame <length=5, flags=0x00, stream_id=9>
(dep_stream_id=7, weight=1, exclusive=0)
[ 0.000] send PRIORITY frame <length=5, flags=0x00, stream_id=11>
(dep_stream_id=3, weight=1, exclusive=0)
[ 0.000] send HEADERS frame <length=49, flags=0x25, stream_id=13>
; END_STREAM | END_HEADERS | PRIORITY
(padlen=0, dep_stream_id=11, weight=16, exclusive=0)
; Open new stream
:method: GET
:path: /abc/efg/hehe
:scheme: http
:authority: 127.0.0.1:5000
accept: */*
accept-encoding: gzip, deflate
user-agent: nghttp2/1.19.0
[ 0.000] recv SETTINGS frame <length=0, flags=0x00, stream_id=0>
(niv=0)
[ 0.000] recv WINDOW_UPDATE frame <length=4, flags=0x00, stream_id=0>
(window_size_increment=983025)
[ 0.000] send SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.000] recv (stream_id=13) :status: 200
[ 0.000] recv (stream_id=13) content-type: application/grpc
[ 0.000] recv (stream_id=13) grpc-status: 12
[ 0.000] recv (stream_id=13) grpc-message: unknown service abc/efg
[ 0.000] recv HEADERS frame <length=56, flags=0x05, stream_id=13>
; END_STREAM | END_HEADERS
(padlen=0)
; First response header
[ 0.000] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
; ACK
(niv=0)
[ 0.000] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
(last_stream_id=0, error_code=NO_ERROR(0x00), opaque_data(0)=[])
grpc服務端自定義的固定頭信息: content-type: application/grpc grpc-status: 12 grpc-message: unknown service abc/efg
小結:
所以,默認的原生http2客戶端與grpc服務端只能夠實現通信,但也不能夠實現完整正確的響應解析。
總結
grpc與原生http2能夠實現協議通信,但在通信包的解釋上有更進一步的特殊處理,從而會導致並不能直接與原生http2協議愉快通信。
比如解釋content-type不能識別時,導致的連接異常主斷開,無法繼續后續的請求與響應。
nghttp 包 幫助調試
啟動原生http2/h2c server端:
nghttpd 5003 --no-tls
發送原生http2請求:
nghttp -v http://127.0.0.1:5000/abc/efg/hehe
如何使用原生http2服務正確地接收並響應grpc請求
了解這個問題,以便在可能時候實現基於原生http2的grpc反向代理。