首先看下我们正常使用HttpClient作POST请求的处理方法
public static String doHttpPost(String url, JSONObject params)
throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(url);
List nvps = new ArrayList();
params.forEach((key, value) -> {
if (value != null) {
nvps.add(new BasicNameValuePair(key, String.valueOf(value)));
} else {
nvps.add(new BasicNameValuePair(key, ""));
}
});
HttpEntity reqEntity = EntityBuilder
.create()
.setContentEncoding('UTF-8")
.setParameters(nvps).build();
httpPost.setEntity(reqEntity);
CloseableHttpResponse response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "UTF-8");
}
EntityUtils.consume(entity);
response.close();
return result;
} finally {
httpclient.close();
}
}
初看之下没有问题,平时使用也经常看不出问题(因为程序员在作请求都会本能规避请求参数中含有中文内容),但是一旦传参params
含有中文,就会在收到的请求中看到???
这种分分钟让程序猿高潮的东西!因为setContentEncoding('UTF-8")
这一句根本没起作用
请求参数的处理主要集中在下面这部分
HttpEntity reqEntity = EntityBuilder.create().setContentEncoding('UTF-8").setParameters(nvps).build();
可以看出是典型的装饰者模式
,通过Maven查看EntityBuilder
源码中的build()
函数如下:
public HttpEntity build() {
final AbstractHttpEntity e;
//... 略 ...
else if (this.parameters != null) {
e = new UrlEncodedFormEntity(this.parameters,
this.contentType != null ? this.contentType.getCharset() : null);
}
//... 略 ...
e.setContentEncoding(this.contentEncoding);
//... 略 ...
return e;
}
可以看到,这个setContentEncoding
不是设置请求参数编码的,参数编码设置是e = new UrlEncodedFormEntity(this.parameters,this.contentType != null ? this.contentType.getCharset() : null);
这一句完成的,所以参数编码要用setContentType()
来设置。再来看ContentType
的源码
public static final ContentType APPLICATION_ATOM_XML = create(
"application/atom+xml", Consts.ISO_8859_1);
public static final ContentType APPLICATION_FORM_URLENCODED = create(
"application/x-www-form-urlencoded", Consts.ISO_8859_1);
public static final ContentType APPLICATION_JSON = create(
"application/json", Consts.UTF_8);
public static final ContentType APPLICATION_OCTET_STREAM = create(
"application/octet-stream", (Charset) null);
public static final ContentType APPLICATION_SVG_XML = create(
"application/svg+xml", Consts.ISO_8859_1);
public static final ContentType APPLICATION_XHTML_XML = create(
"application/xhtml+xml", Consts.ISO_8859_1);
public static final ContentType APPLICATION_XML = create(
"application/xml", Consts.ISO_8859_1);
public static final ContentType MULTIPART_FORM_DATA = create(
"multipart/form-data", Consts.ISO_8859_1);
public static final ContentType TEXT_HTML = create(
"text/html", Consts.ISO_8859_1);
public static final ContentType TEXT_PLAIN = create(
"text/plain", Consts.ISO_8859_1);
public static final ContentType TEXT_XML = create(
"text/xml", Consts.ISO_8859_1);
public static final ContentType WILDCARD = create(
"*/*", (Charset) null);
尼玛,固有的全是ISO_8859_1,要中文啊,还好有ContentType.create(mimeType, charset)
可以用,所以最终完成的代码如下:
public static String doHttpPost(String url, JSONObject params)
throws IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(url);
List nvps = new ArrayList();
params.forEach((key, value) -> {
if (value != null) {
nvps.add(new BasicNameValuePair(key, String.valueOf(value)));
} else {
nvps.add(new BasicNameValuePair(key, ""));
}
});
HttpEntity reqEntity = EntityBuilder
.create()
.setContentType(
ContentType.create(
"application/x-www-form-urlencoded",
Consts.UTF_8)).setParameters(nvps).build();
httpPost.setEntity(reqEntity);
CloseableHttpResponse response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "UTF-8");
}
EntityUtils.consume(entity);
response.close();
return result;
} finally {
httpclient.close();
}
}