http client fluent 报错案例


@RequestMapping(value = "/upload")
public String upload(@RequestParam(value = "file", required = false) MultipartFile file) {
String uploadResult = Request.Post("http://img.g3000.net/file/upload")
.body(MultipartEntityBuilder.create()
.addBinaryBody("file", file.getInputStream(), ContentType.APPLICATION_OCTET_STREAM, "file").build())
.execute().returnContent().asString();
}

在测试HttpClient编写的图片上传程序时抛出以下异常::
[quote]
[ INFO] (RetryExec.java:94) - I/O exception (java.net.SocketException) caught when processing request to {}->http://img.g3000.net:80: Connection reset by peer: socket write error
[ERROR] (ImageService.java:55) - 上传图片异常
org.apache.http.client.ClientProtocolException
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
at org.apache.http.client.fluent.Request.execute(Request.java:143)
at com.g3000.model.service.ImageService.upload(ImageService.java:53)
at com.g3000.controller.FileUpload.uploadUserPhoto(FileUpload.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.g3000.filter.G3000CorsFilter.filterImpl(G3000CorsFilter.java:62)
at com.g3000.filter.G3000CorsFilter.doFilter(G3000CorsFilter.java:42)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:105)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
... 53 more
Caused by: java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
at org.apache.http.impl.io.SessionOutputBufferImpl.streamWrite(SessionOutputBufferImpl.java:123)
at org.apache.http.impl.io.SessionOutputBufferImpl.flushBuffer(SessionOutputBufferImpl.java:135)
at org.apache.http.impl.io.SessionOutputBufferImpl.flush(SessionOutputBufferImpl.java:142)
at org.apache.http.impl.io.ChunkedOutputStream.flush(ChunkedOutputStream.java:194)
at org.apache.http.entity.mime.content.StringBody.writeTo(StringBody.java:182)
at org.apache.http.entity.mime.AbstractMultipartForm.doWriteTo(AbstractMultipartForm.java:150)
at org.apache.http.entity.mime.AbstractMultipartForm.writeTo(AbstractMultipartForm.java:173)
at org.apache.http.entity.mime.MultipartFormEntity.writeTo(MultipartFormEntity.java:97)
at org.apache.http.impl.execchain.RequestEntityProxy.writeTo(RequestEntityProxy.java:116)
at org.apache.http.impl.DefaultBHttpClientConnection.sendRequestEntity(DefaultBHttpClientConnection.java:155)
at org.apache.http.impl.conn.CPoolProxy.sendRequestEntity(CPoolProxy.java:149)
at org.apache.http.protocol.HttpRequestExecutor.doSendRequest(HttpRequestExecutor.java:236)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:121)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:254)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86)
... 55 more
[ INFO] (MemcachedClientFactoryBean.java:62) - [{QA sa=/192.168.6.19:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0}]
[ INFO] (MemcachedClientFactoryBean.java:62) - [{QA sa=/192.168.6.19:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0}]

[/quote]
根据异常信息"Cannot retry request with a non-repeatable request entity. The cause lists the reason the original request failed."可以确定抛出异常的原因是程序中使用了不可重复的请求实体(non-repeatable request entity)。
于是查看官方[url]http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html[/url]HttpClient Tutorial的1.1.4.1. Repeatable entities[url]http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e113[/url]节,内容如下:
[quote]
An entity can be repeatable, meaning its content can be read more than once. This is only possible with self contained entities (like ByteArrayEntity or StringEntity)
[/quote]

根据上面对Repeatable Entity的介绍,就可以确定问题是因为构建multipartEntity时包含除ByteArrayEntity和StringEntity以外的Entity。修改代码如下:


@RequestMapping(value = "/upload")
public String upload(@RequestParam(value = "file", required = false) MultipartFile file) {
String uploadResult = Request.Post("http://img.g3000.net/file/upload")
.body(MultipartEntityBuilder.create()
.addBinaryBody("file", file.getBytes(), ContentType.APPLICATION_OCTET_STREAM, "file")
.build())
.execute().returnContent().asString();
}


验证:


import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.jdom2.JDOMException;

import java.io.*;

public class TestMultipartForm {
public static void main(String[] args) throws IOException, JDOMException {
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://10.5.13.21/upload/");

MultipartEntity multipartEntity = new MultipartEntity();
multipartEntity.addPart("pixel_middle", new StringBody("960,600"));
multipartEntity.addPart("pixel_small", new StringBody("192,120"));
multipartEntity.addPart("system", new StringBody("01"));
multipartEntity.addPart("sort", new StringBody("01"));
multipartEntity.addPart("uploader", new StringBody("0283"));
multipartEntity.addPart("image", new InputStreamBody(new FileInputStream(new File("D:/httpclient/images/0.jpg");), file.getName()));

// 显示实体是否可重复
System.out.println("Repeatable:" + multipartEntity.isRepeatable());

httpPost.setEntity(multipartEntity);
HttpResponse response = httpclient.execute(httpPost);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (200 == statusCode) {
HttpEntity entity = response.getEntity();
System.out.println(EntityUtils.toString(entity));
} else {
System.out.println("Error " + statusCode + "!");
}
} finally {
httpPost.releaseConnection();
}
}
}



编译执行上述程序,结果如下:

Repeatable:false

注释第33行代码,重新编译执行程序,结果如下:

Repeatable:true

根据上面的执行结果,可以确定InputStreamBody是造成multipartEntity为不可重复实体的元凶。

HttpClient有ByteArrayBody、FileBody、InputStreamBody和StringBody四种Body。经过笔者测试,其中只有用InputStreamBody构建multipartEntity才是non-repeatable entity。

总结:

最早使用InputStreamBody而不是FileBody,是因为业务需要前置系统将图片上传到图片服务器,并保存图片链接地址到前置系统的数据库。但是前置系统是B/S架构,图片从页面上传到前置的后台是以流的方式,故而才使用InputStreamBody。最后,使用ByteArrayBody代替InputStreamBody。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值