HttpClient模拟表单提交数据(File(文件)类型和普通类型)
最近在工作中,因为对方要求使用表单进行上传,但是其中有一个字段是file类型,导致我弄了很久,都无法正确发出,在这里进行记录,希望能给大家一种解决思路。
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
public class test {
@Test
public void uploadFormFile() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
int timeOut = 30000;
// 设置本地fiddler代理,方便排查问题
//因为是基于tomcat进行的请求转发,所以在代码中手动添加代理
HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut)
.setConnectTimeout(timeOut).setSocketTimeout(timeOut).setProxy(proxy).build();
//设置请求地址
HttpPost httpPost = new HttpPost("XXXX");
httpPost.setConfig(requestConfig);
/*
* 这里是一个很容易被疏忽的地方
* 关于表单提交,会有两种content-Type:
* 1、application/x-www-form-urlencoded:不能进行文件的上传,我们一般form表单默认就是这个类型
* 2、multipart/form-data ,用于文件的上传,设置表单的MIME编码,二进制传输数据,参数会以boundary进行分割
* 很多人选择文件上传的话,就会直接设置这个地方为multipart/form-data,
* 但是这里面有个boundary参数属性,假如我们手动设置为multipart/form-data,则会导致boundary无法生成。所以这里千万不要设置
*/
//httpPost.setHeader("content-Type", "multipart/form-data");
//构建参数
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
/*
* RFC6532=utf-8,STRICT=iso-8859-1
* 这里如果存在中文乱码,一定要用RFC6532
* 如果没有中文,这行可以不要
*/
multipartEntityBuilder.setMode(HttpMultipartMode.RFC6532);
/*
* 这个设置并无卵用,害我纠结了半天是不是编码方式设置错了
*/
//multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
/*
* 这个地方是个深渊巨坑!!!!
* 这里千万不要设置ContentType = multipart/form-data, 不然 boundary 这个参数就不会自动生成
*/
//org.apache.http.entity.ContentType.create("multipart/form-data",Charset.forName("UTF-8"));
/*
* 这里也是个深渊巨坑!!!!
* 这里是设置需要传输的文件
* 第一个参数是key值,也就是对面拿什么来接收
* 第二个参数是文件 file
* 第三个参数 一种类型,具体也也不太清楚
* 第四个参数 这个就是巨坑了!!看源码,当不填这个值的时候,会取file.getName;
* 但是一定要记住,如果文件是远程地址的,这样再通过http传的时候会出现错误,所以需要取到最原始的文件后缀名!!!最好就是用字节流去读取这个文件
*
* 这里的第三个参数和第四个参数必须要设置,不然后续服务读取不到这个文件流
*/
File file = new File("http://aaa/bbb/cc/ddd.jpg");
multipartEntityBuilder.addBinaryBody("image", file, ContentType.DEFAULT_BINARY, file.getName());
//这里是设置string类型的传输数据
/*
* 这里是设置字符编码
* 这个地方也是坑,但是网上很多文章都会设置,所以很少人出问题
* 根据我的理解,就是整体传输,需要给表单设置一个编码,然后文件传输,也需要设置编码,文字传输,也需要设置编码
* 很多小伙伴都会因为某个地方没有设置编码,导致传输失败。这个地方可能理解有误,欢迎大家来指导。
*/
org.apache.http.entity.ContentType contentType =
org.apache.http.entity.ContentType.create("text/plain",Charset.forName("UTF-8"));
multipartEntityBuilder.addPart("name", new StringBody("zhangsan", contentType));
multipartEntityBuilder.addPart("age", new StringBody("18", contentType));
httpPost.setEntity(multipartEntityBuilder.build());
try {
org.apache.http.HttpResponse response = httpClient.execute(httpPost);
/*
* int statusCode= response.getStatusLine().getStatusCode();
* 这里是返回状态码,真正在项目中,需要判断返回码是否为200,看是否发送成功
* 这里就不展开写了
*/
System.out.println( EntityUtils.toString(response.getEntity(), "UTF-8"));
} catch (Exception e) {
}finally {
try {
httpClient.close();
} catch (IOException e) {
}
}
}
}
这里还再提供一种普通写法,比较简单,不涉及到文件上传。使用NameValuePair,content-Type为application/x-www-form-urlencoded。
@Test
public void testForm() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
int timeOut = 30000;
// 设置本地fiddler代理,方便排查问题
//因为是基于tomcat进行的请求转发,所以在代码中手动添加代理
HttpHost proxy = new HttpHost("127.0.0.1", 8080, "http");
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(timeOut)
.setConnectTimeout(timeOut).setSocketTimeout(timeOut).setProxy(proxy).build();
//设置请求地址
HttpPost httpPost = new HttpPost("XXXX");
httpPost.setConfig(requestConfig);
httpPost.setHeader("content-Type", "application/x-www-form-urlencoded");
List<NameValuePair> formParams = new ArrayList<>();
formParams.add(new BasicNameValuePair("isAllIndustry", "0"));
try {
UrlEncodedFormEntity he=new UrlEncodedFormEntity(formParams,"UTF-8");
httpPost.setEntity(he);
HttpResponse response=httpClient.execute(httpPost);
System.out.println( EntityUtils.toString(response.getEntity(), "UTF-8"));
} catch (Exception e) {
// TODO: handle exception
}
参考:
https://www.cnblogs.com/evasean/archive/2018/07/25/9368670.html
http://www.cnblogs.com/iscys/p/9595358.html
https://yq.aliyun.com/ziliao/286006