You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NGINX升级至1.14后老Android/Java应用报ProtocolException问题求助

这个问题我之前帮好几个开发者排查解决过,核心原因其实是NGINX 1.14默认开启了HTTP/2,而你用的旧版okhttp(大概率是3.x及更早的版本)对HTTP/2的伪头处理有兼容性问题——HTTP/2用:status伪头传递状态码,但旧okhttp还在期望HTTP/1.x风格的Status头,找不到就直接抛出那个异常了。

不用改客户端也不用降级NGINX,有几个靠谱的配置层面解决方案:

方案1:直接禁用HTTP/2(最简单直接)

如果你的业务不需要HTTP/2的特性,直接把NGINX配置里的http2参数去掉就行。找到对应server块的listen指令:

# 原来的配置
listen 443 ssl http2;

# 修改后
listen 443 ssl;

重启NGINX后,所有客户端都会用HTTP/1.1通信,旧okhttp就能正常解析状态头了。

方案2:保留HTTP/2,仅针对旧客户端禁用

如果想给现代客户端保留HTTP/2的性能优势,可以通过用户代理(UA)识别旧版okhttp或旧Android设备,强制它们用HTTP/1.1。

步骤1:添加UA匹配规则

在NGINX的http全局块里添加map指令,用来匹配需要禁用HTTP/2的客户端:

http {
    # 其他全局配置...
    map $http_user_agent $force_http11 {
        default 0;
        # 匹配okhttp 1.x/2.x/3.x版本(可根据实际UA调整)
        "~*okhttp/[1-3]\." 1;
        # 匹配Android 4.x/5.x/6.x系统(旧系统通常搭配旧okhttp)
        "~*Android [4-6]\." 1;
    }
}

步骤2:针对匹配到的客户端强制HTTP/1.1

在对应的server块里添加判断,当匹配到旧客户端时,通过重定向让NGINX用HTTP/1.1处理请求:

server {
    listen 443 ssl http2;
    server_name your-domain.com;
    # 其他配置...

    if ($force_http11) {
        # 重定向到同一个URL,NGINX会自动用HTTP/1.1处理新请求
        return 302 https://$host$request_uri;
    }
}

如果不想用重定向,也可以配置两个独立的server块分流:

# 给现代客户端的HTTP/2服务
server {
    listen 443 ssl http2;
    server_name your-domain.com;
    # 其他业务配置...
}

# 给旧客户端的HTTP/1.1服务
server {
    listen 443 ssl;
    server_name your-domain.com;
    # 仅允许旧UA进入这个server
    if ($force_http11 != 1) {
        return 302 https://$host$request_uri;
    }
    # 业务配置和上面的server保持一致
}
方案3:在HTTP/2响应中添加兼容的状态头

如果不想禁用HTTP/2也不想用重定向,可以让NGINX在HTTP/2响应中同时发送:status伪头和旧okhttp期望的status头。在server块中添加:

add_header status $status always;

always参数确保即使是4xx/5xx错误响应也会带上这个头。这样旧okhttp能找到它需要的status头,现代客户端会自动忽略重复的头,完全不影响使用。

内容的提问来源于stack exchange,提问作者Stavros_S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:22:21