如何让发起HTTP/2连接的客户端降级至HTTP/1.1?
Let’s break down your scenario first: you’ve got a server that only supports HTTP/1.1 (no full HTTP/2 support), and you need to handle clients that initiate connections with the HTTP/2 connection prefix (PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n) — not the ones using the HTTP/1.1 Upgrade header. Your goal is to tell these clients to switch to HTTP/1.1, but your attempts with HTTP/2 frames and HTTP/1.1 505 responses haven’t worked as expected.
What You’ve Tried (and Why It Failed)
You tested sending combinations of empty SETTINGS frames, RST_STREAM frames with the HTTP_1_1_REQUIRED (0xd) error code, and GOAWAY frames, but saw:
nghttpthrew a protocol error, since it expected valid HTTP/2 flow after receiving the SETTINGS framecurlreported a framing layer error, as it interpreted the HTTP/2 frames as a broken HTTP/2 session
The core issue here is that sending HTTP/2 frames tells the client "I do support HTTP/2, but there’s a problem with this request/connection" — not "I don’t support HTTP/2 at all". So the client won’t trigger a downgrade to HTTP/1.1; it’ll just abort the HTTP/2 session.
The Correct Approach: Skip HTTP/2 Frames Entirely
When a client sends the HTTP/2 connection prefix to an HTTP/1.1-only server, the right move is to ignore the HTTP/2 prefix entirely and send a standard HTTP/1.1 error response. No HTTP/2 frames needed — this is the signal the client needs to realize your server doesn’t speak HTTP/2.
Recommended Response Format
Send either a 426 Upgrade Required or 505 HTTP Version Not Supported response, formatted strictly according to HTTP/1.1 rules. For example:
HTTP/1.1 505 HTTP Version Not Supported Content-Type: text/plain Content-Length: 47 This server only supports HTTP/1.1. Please retry with it.
Or:
HTTP/1.1 426 Upgrade Required Content-Type: text/plain Content-Length: 39 Please use HTTP/1.1 to communicate with this server.
How to Test This
Use netcat to simulate the server with this response:
echo -e "HTTP/1.1 505 HTTP Version Not Supported\r\nContent-Type: text/plain\r\nContent-Length: 47\r\n\r\nThis server only supports HTTP/1.1. Please retry with it." | netcat -l -p 8888 -s 127.0.0.1
Then test with curl:
curl -v --http2-prior-knowledge http://127.0.0.1:8888
You’ll see curl receive the 505 response clearly. Smart clients may even automatically retry with HTTP/1.1, but at minimum, the error message will guide the client to switch protocols.
Key Takeaways
- Don’t send HTTP/2 frames: Any HTTP/2 frame tells the client your server supports HTTP/2, which prevents downgrade.
- Stick to HTTP/1.1 formatting: Make sure your response uses
\r\nfor line breaks, includes a validContent-Length(orTransfer-Encoding: chunked), and follows HTTP/1.1 structure. - Choose the right status code: 505 is explicit about version support, while 426 is more about requiring a specific protocol — either works, but 505 is more direct for this scenario.
内容的提问来源于stack exchange,提问作者Daniel Jour

