1. 程式人生 > >request.getContentLength()的值為-1的問題解決方案【HttpPost發起】

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);