request.getContentLength()的值為-1的問題解決方案【HttpPost發起】
1、問題的發現,服務端使用DataInputStream的方式獲取流,直接上程式碼說明
try { DataInputStream in = new DataInputStream(request.getInputStream()); // 將請求訊息的實體送到b變數中 int totalBytes = request.getContentLength(); byte[] b = new byte[totalBytes]; in.readFully(b); in.close(); String reqContent = new String(b, "UTF-8"); respXml = reqContent; } catch (IOException e) { e.printStackTrace(); }
DataInputStream的readFully()需要創新一個與流等長的Byte陣列,因為request.getContentLength()的值為-1,讀取失敗。
2、於是想服務端換一種方式讀取,可以規避問題,但是沒有解決問題,而且服務端一般是你上游的,你動不了,也不一定會配合你改,以為別的接入可以,為啥你不行,一般都會被懟回來,自討沒趣,但是程式碼還是要上的。
InputStream inputStream = request.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); StringBuffer msgBuf = new StringBuffer(); String temp = null; while((temp = br.readLine())!=null){ msgBuf.append(temp); } respXml= msgBuf.toString();
3、針對request.getContentLength()的值為-1,其實就是客戶端傳送的得資料流的採用的HTTP協議header的Content-Length引數中沒有值,於是,準備強制性真進行賦值post.setHeader("Content-Length", xml.getBytes("UTF-8").length+"");,結果提示Caused by: org.apache.http.ProtocolException: Content-Length header already present。於是再次檢查客服端程式碼。InputStreamEntity有四個構造方法,如果不提供長度,預設為-1。因為使用沒有length的構造
InputStream inputStream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
InputStreamEntity inputEntry = new InputStreamEntity(inputStream);
導致request.getContentLength()的值為-1的建構函式原始碼如下;
/**
* Creates an entity with an unknown length.
* Equivalent to {@code new InputStreamEntity(instream, -1)}.
*
* @param instream input stream
* @throws IllegalArgumentException if {@code instream} is {@code null}
* @since 4.3
*/
public InputStreamEntity(final InputStream instream) {
this(instream, -1);
}
正確的因為使用下面二個建構函式,建立InputStreamEntity。
/**
* Creates an entity with a specified content length.
*
* @param instream input stream
* @param length of the input stream, {@code -1} if unknown
* @throws IllegalArgumentException if {@code instream} is {@code null}
*/
public InputStreamEntity(final InputStream instream, final long length) {
this(instream, length, null);
}
繼續看原始碼發現post.setEntity(reqentity);InputStreamEntity extends AbstractHttpEntity;而AbstractHttpEntity implements HttpEntity;4.0以後StringEntity extends AbstractHttpEntity,於是是否能用StringEntity來解決問題呢,小試牛刀可以,直接上程式碼。
HttpEntity reqentity = new StringEntity(xml, ContentType.create("application/xml", "UTF-8"));
post.setEntity(reqentity);
PS:最後有些部落格說在header中新增post.setHeader("Accept-Encoding", "identity");我沒有成功,從我有些的知識感覺問題是Content-Length沒有值或者值不對,不知道跟Accept-Encoding有啥關係,知道的大牛可以留言。最後上一個全乎的程式碼。
String xml="";
CloseableHttpClient httpclient = HttpClients.createDefault();
CloseableHttpResponse httpResponse = null;
HttpPost post = new HttpPost("http://127.0.0.1:8888/xxx");
HttpEntity entity = null;
String result = null;
try {
/***解決方案一**/
// HttpEntity reqentity = new StringEntity(xml, ContentType.create("application/xml", "UTF-8"));
// post.setEntity(reqentity);
/***解決方案二**/
InputStream inputStream = new ByteArrayInputStream(xml.getBytes("UTF-8"));
InputStreamEntity inputEntry = new InputStreamEntity(inputStream,xml.getBytes("utf-8").length);
post.setEntity(inputEntry);
httpResponse=httpclient.execute(post);
if(httpResponse.getStatusLine().getStatusCode()==HttpStatus.SC_OK) {
entity=httpResponse.getEntity();
result=EntityUtils.toString(entity, "UTF-8");
}
EntityUtils.consume(entity);
httpResponse.close();
} catch (Exception e) {
e.printStackTrace();
}
logger.info("返回報文:\r\n"+result);