当前位置 博文首页 > 闫玉林的博客:java使用http post方法提交json数据(不乱码)

    闫玉林的博客:java使用http post方法提交json数据(不乱码)

    作者:[db:作者] 时间:2021-08-17 18:54

    问题

    • 需要调用第三方接口发送短信,必须使用post方法,请求和返回都是JSON格式数据,编码要求UTF-8
    • 项目中已有的 HttpUtil 工具类中,有post方法,但是请求此接口没有任何返回;使用curl发送post请求,有数据返回,说明接口没问题
    • 看了下对方接口文档,要求json,应该是需要将json数据放入请求体,只好再加一个post方法了。
    • 重新写了个新方法后,接口能正常访问了。但是新问题来了,中文乱码。明明设置UTF-8,还是不行。下面说下解决方法,并贴上代码。

    解决

    • 首先思路要明确,post无数据返回,应该是没遵守对方的接口要求,果断将json格式数据放入请求体,第一个问题解决。
    • 中文乱码,肯定是编码格式问题。虽然设置了UTF-8,但肯定是没设置好。看了下源码,果然是代码写的有问题。
        /**
         * post提交json数据
         * @param url
         * @param json
         * @return
         */
        public static JSONObject doPost(String url, JSONObject json){
            CloseableHttpClient httpclient = HttpClientBuilder.create().build();
            HttpPost post = new HttpPost(url);
            JSONObject response = null;
            try {
    //            StringEntity s = new StringEntity(json.toString());
    //            s.setContentEncoding("UTF-8");
                //上面为乱码出错版本
                StringEntity s = new StringEntity(json.toString(),"UTF-8");
                s.setContentType("application/json");//发送json数据需要设置contentType
                post.setEntity(s);
                HttpResponse res = httpclient.execute(post);
                if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                    String result = EntityUtils.toString(res.getEntity());// 返回json格式:
                    response = JSONObject.parseObject(result);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            logger.info("执行HTTP Post请求" + url + "时,结果:{}", response);
            return response;
        }
    

    探究

    • 由于短信接口有可信ip限制,必须在服务器上测试,使用curl提交post请求很方便,很实用,需要的可以拿走参考。
    curl -H "Content-Type: application/json" -X POST -d '{"senderSystem": "xxx", "authCode":"xxx", "receiverUser":"111", "msgType":"2","content":中文内容" }' "http://xxx:xx/xxx/message/send"
    
    • 针对乱码问题,主要是StringEntity类的2个不同的构造器,起不同的作用
    • 构造器StringEntity(String string)使用的是默认编码Consts.ISO_8859_1,在new创建对象时,数据已经被转码了,后面再设置UTF-8也没有用了。
    • 构造器StringEntity(String string, String charset)会根据传递的编码格式转码,所以结果符合自己需求。
    	//org.apache.http.entity.StringEntity类
    	public StringEntity(String string, String charset) throws UnsupportedCharsetException {
            this(string, ContentType.create(ContentType.TEXT_PLAIN.getMimeType(), charset));
        }
    	//使用默认编码
        public StringEntity(String string) throws UnsupportedEncodingException {
            this(string, ContentType.DEFAULT_TEXT);
        }
    
    	// org.apache.http.entity.ContentType类,默认DEFAULT_TEXT 取自TEXT_PLAIN,即 Consts.ISO_8859_1
    	static {
            APPLICATION_ATOM_XML = create("application/atom+xml", Consts.ISO_8859_1);
            APPLICATION_FORM_URLENCODED = create("application/x-www-form-urlencoded", Consts.ISO_8859_1);
            APPLICATION_JSON = create("application/json", Consts.UTF_8);
            APPLICATION_OCTET_STREAM = create("application/octet-stream", (Charset)null);
            APPLICATION_SVG_XML = create("application/svg+xml", Consts.ISO_8859_1);
            APPLICATION_XHTML_XML = create("application/xhtml+xml", Consts.ISO_8859_1);
            APPLICATION_XML = create("application/xml", Consts.ISO_8859_1);
            MULTIPART_FORM_DATA = create("multipart/form-data", Consts.ISO_8859_1);
            TEXT_HTML = create("text/html", Consts.ISO_8859_1);
            TEXT_PLAIN = create("text/plain", Consts.ISO_8859_1);
            TEXT_XML = create("text/xml", Consts.ISO_8859_1);
            WILDCARD = create("*/*", (Charset)null);
            DEFAULT_TEXT = TEXT_PLAIN;
            DEFAULT_BINARY = APPLICATION_OCTET_STREAM;
        }
    
    cs