使用nghttp2_asio搭建服务出现ERR_EMPTY_RESPONSE空响应错误如何解决
问题根因
你部署的nghttp2_asio服务默认仅支持HTTP/2明文(h2c)直接协商模式,普通Chrome、Firefox浏览器以及未加特殊参数的curl发起HTTP请求时,默认都会先发送HTTP/1.1格式的请求头,不会直接发送HTTP/2二进制帧,服务端无法解析HTTP/1.1请求,所以返回空响应。只有携带--http2-prior-knowledge参数的curl会直接发送HTTP/2帧,因此可以正常得到响应。
可行解决方案
方案1:配置TLS加密(最推荐,兼容所有主流浏览器)
主流浏览器的HTTP/2协议默认基于TLS层的ALPN扩展完成协商,无需用户手动处理协议切换,你可以修改代码添加TLS配置:- 提前准备好SSL证书文件(公钥
fullchain.pem、私钥privkey.pem,可以用openssl自签测试) - 修改服务代码如下:
#include "bits/stdc++.h" #include "nghttp2/asio_http2_server.h" using namespace std; using namespace nghttp2::asio_http2; using namespace nghttp2::asio_http2::server; int main(int argc, char **argv) { http2 srv; srv.num_threads(4); srv.handle("/", [](const request &req, const response &res) { cout << req.uri().path << endl; header_map headers; headers.emplace("content-type", header_value{ "text/html", false }); res.write_head(200, headers); res.end(file_generator("index.html")); }); // 新增TLS配置 boost::asio::ssl::context tls_ctx(boost::asio::ssl::context::sslv23); tls_ctx.set_options( boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use ); // 加载证书和私钥文件 tls_ctx.use_certificate_chain_file("fullchain.pem"); tls_ctx.use_private_key_file("privkey.pem", boost::asio::ssl::context::pem); boost::system::error_code ec; // 替换原有监听逻辑,传入TLS配置 if (srv.listen_and_serve(ec, tls_ctx, "localhost", "8443")) { cerr << ec.message() << endl; } return 0; }配置完成后访问
https://localhost:8443,浏览器会自动协商使用HTTP/2,无需额外配置。- 提前准备好SSL证书文件(公钥
方案2:前置反向代理完成协议转换
如果你不想修改原有服务代码,可以在服务前部署Nginx作为反向代理,由Nginx处理用户的HTTP/1.1请求,再通过h2c直连模式转发到你的nghttp2_asio服务,参考Nginx配置:server { listen 80; server_name localhost; location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 2; proxy_set_header Connection ""; } }配置完成后直接访问Nginx监听的80端口即可正常请求。
方案3:代码中添加HTTP/1.1升级逻辑
可以在现有服务基础上新增HTTP/1.1请求解析逻辑,收到带有Upgrade: h2c头的HTTP/1.1请求时返回101切换协议响应,后续通信使用HTTP/2。该方案实现成本较高,且部分老旧浏览器不支持h2c升级,通用性不如前两种方案。
内容的提问来源于stack exchange,提问作者M3601
相关产品推荐
相关产品推荐

