HttpURLConnection 中出现java.net.ProtocolException: cannot write request body after response has been read
HttpURLConnection是Android原生自带的网库请求框架,因为轻量级的原因很多SDK会使用到它,最近在项目中频繁出现java.net.ProtocolException: cannot write request body after response has been read,通过排查是某个SDK中使用到了HttpURLConnection导致的,代码如下:
private static void b(String urlStr, boolean isPost, boolean jsonTyp, String params, Network network) {
DataOutputStream dataOutputStream = null;
HttpURLConnection httpURLConnection = null;
boolean requestSuccess = false;
label:
{
try {
requestSuccess = true;
URL url = new URL(urlStr);
if (network != null && Build.VERSION.SDK_INT >= 21) {
httpURLConnection = (HttpURLConnection) network.openConnection(url);
} else {
httpURLConnection = (HttpURLConnection) url.openConnection();
}
httpURLConnection.setConnectTimeout(10000);
httpURLConnection.setReadTimeout(10000);
httpURLConnection.setDoInput(true);
if (isPost) {
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setDoOutput(true);
} else {
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setDoOutput(false);
}
httpURLConnection.setUseCaches(false);
httpURLConnection.setInstanceFollowRedirects(true);
if (jsonTyp) {
httpURLConnection.setRequestProperty("Content-Type", "application/json");
} else {
httpURLConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
}
httpURLConnection.setRequestProperty("connection", "Keep-Alive");
//1 httpURLConnection.connect(); 引起异常的代码
httpURLConnection.connect();
if (params != null) {
//2 httpURLConnection.getOutputStream()
dataOutputStream = new DataOutputStream(httpURLConnection.getOutputStream());
byte[] paramsBytes = params.getBytes("UTF-8");
dataOutputStream.write(paramsBytes, 0, paramsBytes.length);
dataOutputStream.flush();
dataOutputStream.close();
}
if (httpURLConnection.getResponseCode() != 200) {
if (httpURLConnection.getResponseCode() == 302) {
String locationUrl;
if ((locationUrl = httpURLConnection.getHeaderField("Location")) != null && !locationUrl.isEmpty()) {
b(locationUrl, isPost, jsonTyp, params, network);
requestSuccess = false;
} else {
requestSuccess = false;
}
} else {
requestSuccess = false;
}
} else {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
StringBuffer stringBuffer = new StringBuffer();
String tempStr;
while ((tempStr = bufferedReader.readLine()) != null) {
tempStr = new String(tempStr.getBytes("UTF-8"));
stringBuffer.append(tempStr);
}
bufferedReader.close();
requestSuccess = false;
}
break label;
} catch (Exception e) {
e.printStackTrace();
requestSuccess = false;
} finally {
if (requestSuccess) {
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
return;
} catch (IOException e) {
e.printStackTrace();
return;
}
}
return;
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException var23) {
var23.printStackTrace();
}
}
}
在HttpURLConnection系统底层使用的Okhttp,getOutputStream()在com.squareup.okhttp.internal.hucHttp.URLConnectionImpl源码:
@Override public final OutputStream getOutputStream() throws IOException {
connect();
BufferedSink sink = httpEngine.getBufferedRequestBody();
if (sink == null) {
throw new ProtocolException("method does not support a request body: " + method);
} else if (httpEngine.hasResponse()) {
throw new ProtocolException("cannot write request body after response has been read");
}
return sink.outputStream();
}
显而易见,当httpEngine.hasResponse() 不等于null时候就会触发这个异常
解决办法就是使用到getOutputStream()的时候前面就不要调用connect()了,因为getOutputStream内部会检查调用connect()