Android 6(Marshmallow)中Volley仅返回ServerError Code:400问题排查
解决Android 6上Volley GET请求报400错误的问题
我之前也碰到过几乎一模一样的场景!Android 6(Marshmallow)上某个Volley GET请求总是触发onErrorResponse,错误码400但没具体消息,其他请求正常,浏览器也能访问,加了请求头也没用对吧?结合我的踩坑经验,给你几个排查方向:
1. 优先检查URL编码问题
Android 6的Volley对URL中特殊字符的编码处理和高版本Android有差异,比如URL里的中文、空格、或者&/=这类符号的特殊组合,高版本可能自动帮你编码了,但Android 6的Volley没处理到位,导致服务端解析失败返回400。
解决办法是手动编码URL的查询参数:
// 比如你的参数是name和value,分别编码后再拼接 String paramName = URLEncoder.encode("参数名", "UTF-8"); String paramValue = URLEncoder.encode("参数值(可能含特殊字符)", "UTF-8"); String url = "https://你的域名/api?" + paramName + "=" + paramValue;
2. 匹配浏览器的User-Agent请求头
有些服务端会校验请求的User-Agent,Android 6的Volley默认的User-Agent和浏览器差异很大,可能被服务端拦截返回400。你可以手动设置和浏览器一致的User-Agent:
StringRequest request = new StringRequest(Request.Method.GET, url, response -> { /* 成功回调 */ }, error -> { /* 错误回调 */ }) { @Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<>(); // 这里用Chrome的User-Agent示例,你可以复制自己浏览器的 headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"); return headers; } };
3. 强制Volley使用TLS 1.2
Android 6默认只支持到TLS 1.1,如果你的服务端已经禁用了旧版TLS协议,会导致SSL握手失败,有些服务端会把这种错误映射成400返回。这时候需要让Volley强制使用TLS 1.2:
首先自定义一个TLSSocketFactory:
public class TLSSocketFactory extends SSLSocketFactory { private SSLSocketFactory internalSSLSocketFactory; public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException { SSLContext context = SSLContext.getInstance("TLSv1.2"); context.init(null, null, null); internalSSLSocketFactory = context.getSocketFactory(); } @Override public String[] getDefaultCipherSuites() { return internalSSLSocketFactory.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return internalSSLSocketFactory.getSupportedCipherSuites(); } @Override public Socket createSocket() throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket()); } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); } private Socket enableTLSOnSocket(Socket socket) { if(socket instanceof SSLSocket) { ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"}); } return socket; } }
然后创建RequestQueue时使用这个自定义栈:
try { TLSSocketFactory tlsSocketFactory = new TLSSocketFactory(); HttpStack stack = new HurlStack(null, tlsSocketFactory); RequestQueue queue = Volley.newRequestQueue(context, stack); queue.add(request); } catch (KeyManagementException | NoSuchAlgorithmException e) { e.printStackTrace(); }
4. 补充缺失的请求头
Android 6的Volley可能默认缺少一些浏览器常见的请求头,比如Accept、Accept-Encoding等,尝试手动添加这些头:
@Override public Map<String, String> getHeaders() throws AuthFailureError { Map<String, String> headers = new HashMap<>(); headers.put("Accept", "*/*"); headers.put("Accept-Encoding", "gzip, deflate"); headers.put("Connection", "keep-alive"); return headers; }
建议你按照从易到难的顺序排查:先检查URL编码,再试修改User-Agent,最后考虑TLS的问题,大概率能解决!
内容的提问来源于stack exchange,提问作者BVtp
相关产品推荐
相关产品推荐

