HttpClient 请求参数中文编码问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ErErFei/article/details/78893696
  • 目录

问题

首先看下我们正常使用HttpClient作POST请求的处理方法

public static String doHttpPost(String url, JSONObject params)
            throws IOException {
    CloseableHttpClient httpclient = HttpClients.createDefault();
    try {
        HttpPost httpPost = new HttpPost(url);

        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        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<NameValuePair> nvps = new ArrayList<NameValuePair>();
        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();
    }
}

猜你喜欢

转载自blog.csdn.net/ErErFei/article/details/78893696