Jackson-> Jackson + HttpPost =“无效的UTF-8中间字节”,设置Mime和编码 [英] Jackson->Jackson + HttpPost = "Invalid UTF-8 middle byte", Setting Mime and Encoding

查看:210
本文介绍了Jackson-> Jackson + HttpPost =“无效的UTF-8中间字节”,设置Mime和编码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的客户端使用Apache HTTP Client libs和Jackson。当我将JSON发布到服务器时,我收到错误:

I'm using the Apache HTTP Client libs and Jackson in my client. When I post JSON to the server I get the error:

org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0x65
 at [Source: HttpInputOverHTTP@22a4ac95; line: 1, column: 81]

如果我没有设置任何标题而不是我无效的媒体类型,这是有道理的。

If I don't set any headers than I get invalid media type, which makes sense.

如果我使用curl和相同的标题,服务器会接受它,所以我认为服务器没问题(只是巧合,它也使用了杰克逊)

If I use curl and the same headers, the server accepts it, so I think the server is OK (and just a coincidence that it's also using Jackson)

这些是文件;我只使用8位字符将其硬编码为Java文字,以避免任何其他地方发生错位

These is the document; I've hard coded it as a Java literal using only 8 bit characters to avoid any other place for mangling to happen

// "Stra\u00DFe" = "Straße"
static String TINY_UTF8_DOC = "[{ \"id\" : \"2\", \"fields\" : { \"subject\" : [{ \"name\" : \"subject\", \"value\" : \"Stra\u00DFe\" }] } }]";

这是我一直在使用的代码,以及各种尝试的评论:

Here's the code I've been using, and comments with the various attempts:

HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost( url );

// Attempt A
// post.setEntity(  new StringEntity( content )  );

// Attempt B
// post.setEntity(  new StringEntity( content )  );
// post.setHeader("Content-Type", "application/json; charset=utf-8");

// Attempt C
// post.setEntity(  new StringEntity( content, ContentType.create("application/json") )  );

// Attempt D
// post.setEntity(  new StringEntity( content, ContentType.create("application/json; charset=UTF-8") )  );

// Attempt F
// post.setEntity(  new StringEntity( content, ContentType.create("application/json; charset=utf-8") )  );

// Attempt G
// StringEntity params = new StringEntity( content );
// params.setContentType("application/json; charset=UTF-8");
// post.setEntity(params);

// And then send to server
HttpResponse response = httpClient.execute( post );
int code = response.getStatusLine().getStatusCode();
// ...etc...

我注意到的其他奇怪的事情:

Other weird things I've noticed:


  • 有一段时间,Mac上的Eclipse与在Linux上运行.jar的行为有所不同;显然这是特定于平台的编码或解码的症状,但我不知道在哪里。具有讽刺意味的是,当我设置Eclipse将代码视为UTF-8(对比ASCII)时破坏我怀疑这是一个重要的线索,但不确定它适合的位置。

  • 我已经看过时间而不是2个字节流中有4个字节,虽然这可能是写入磁盘时不同的编码问题,尽管我是专门在文件IO上设置UTF-8

  • 当我查看调试器中的字符串实体时,我看到了字节,但是8位字符是负数。当你运行Two's Compliment数学时,它仍然是正确的Unicode代码点,所以名义上可以,假设httpclient没有错误。

  • For a while this behaved differently on Eclipse on the Mac vs. running a .jar on Linux; clearly that's a symptom of platform-specific encoding or decoding, but I don't know where. Ironically that broke when I set Eclipse to treat code as UTF-8 (vs. ASCII) I suspect this is an important clue, but not sure where it fits.
  • I've seen times when instead of 2 bytes there's 4 bytes in the stream, though this might have been a different encoding problem when writing to disk, though I was specifically setting UTF-8 on file IO
  • When I look at the string entity in the debugger, I see the bytes, but the 8-bit character is a negative number. When you run through the Two's Compliment math, it is still the correct Unicode code point, so nominally OK, assuming httpclient isn't buggy.

真的没有想法,正如我所说,它适用于卷曲,所以我认为服务器没问题。

Really out of ideas, and as I said, it works with curl, so I think the server is OK.

编辑:

curl在发布到服务器时有效,但我无法共享服务器代码。有人指出,由于curl不是用Java编写的,所以它的行为可能不同,因此服务器代码仍然可能会被怀疑。

curl works when posting to the server, but I can't share the server code. It was pointed out that since curl isn't written in Java, and so perhaps it behaves differently, and therefore the server code could still be suspect.

所以进一步说测试时,下面的代码 NOT 使用Apache httpclient库,并且在发布到服务器时可以正常工作。这证明服务器很好,而且我在客户端使用Apache库的方式仍然有问题(或者可能是它的错误)。

So as a further test, the code below does NOT use the Apache httpclient library, and DOES work when posting to the server. This proves that the server is fine and there's still something wrong with how I'm using the Apache library on the client side (or maybe it's buggy).

非apache-httpclient代码,它可以工作:

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

class PostUtf8 {
    static String POST_URL = "http://...";

    // \u00DF = LATIN SMALL LETTER SHARP S, looks like letter B
    static String TINY_UTF8_DOC = "[{ \"id\" : \"2\", \"fields\" : { \"subject\" : [{ \"name\" : \"subject\", \"value\" : \"Stra\u00DFe\" }] } }]";

    public static void main( String [] args ) throws Exception {
        System.out.println( "Posting to " + POST_URL );
        URL url = new URL( POST_URL );
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestProperty( "Content-Type", "application/json; charset=UTF-8" );
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        OutputStream sout = conn.getOutputStream();
        OutputStreamWriter wout = new OutputStreamWriter(sout, "UTF-8" );
        wout.write( TINY_UTF8_DOC );
        wout.flush();
        int result = conn.getResponseCode();
        System.out.println( "Result = " + result );
    }
}


推荐答案

它看起来问题是如何创建HttpClient的 StringEntity 构造函数的 ContentType 参数。

It looks like the problem is how the ContentType parameter for the HttpClient's StringEntity constructor is being created.

使用 ContentType.APPLICATION_JSON 常量作为参数(对应于application / json; charset = utf -8哑剧型让一切顺利。

Using the ContentType.APPLICATION_JSON constant as a parameter (which corresponds to the "application/json; charset=utf-8" mime type) makes everything work.

这是一个将JSON字符串发布到公共http服务的示例,该服务将请求回送给客户端:

Here is an example posting the JSON string to a public http service that echoes the request back to the client:

public class HttpClientEncoding {

    static String TINY_UTF8_DOC = "[{ \"id\" : \"2\", \"fields\" : { \"subject\" : " +
            "[{ \"name\" : \"subject\", \"value\" : \"Stra\u00DFe\" }] } }]";

    public static void main(String[] args) throws IOException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpPost post = new HttpPost("http://httpbin.org/post");
        StringEntity entity = new StringEntity(TINY_UTF8_DOC, ContentType.APPLICATION_JSON);
        //StringEntity entity = new StringEntity(TINY_UTF8_DOC, ContentType.create("application/json; charset=utf-8"));
        post.setEntity(entity);
        HttpResponse response = httpClient.execute(post);
        String result = EntityUtils.toString(response.getEntity());
        System.out.println(result);
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = mapper.readValue(result, JsonNode.class);
        System.out.println(node.get("json").get(0).get("fields").get("subject").get(0).get("value").asText());
    }
}

输出:

{
  "origin": "46.9.77.167",
  "url": "http://httpbin.org/post",
  "args": {},
  "data": "[{ \"id\" : \"2\", \"fields\" : { \"subject\" : [{ \"name\" : \"subject\", \"value\" : \"Stra\u00dfe\" }] } }]",
  "files": {},
  "form": {},
  "headers": {
    "Content-Length": "90",
    "User-Agent": "Apache-HttpClient/4.3.3 (java 1.5)",
    "Host": "httpbin.org",
    "Connection": "close",
    "X-Request-Id": "c02864cc-a1d6-434c-9cff-1f6187ceb080",
    "Content-Type": "application/json; charset=UTF-8"
  },
  "json": [
    {
      "id": "2",
      "fields": {
        "subject": [
          {
            "value": "Stra\u00dfe",
            "name": "subject"
          }
        ]
      }
    }
  ]
}
Straße

这篇关于Jackson-> Jackson + HttpPost =“无效的UTF-8中间字节”,设置Mime和编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆