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