Jackson-> Jackson + HttpPost ="无效的UTF-8中间字节",设置Mime和编码

Mar*_*ett 8 java json utf-8 jackson

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

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

如果我没有设置任何标题invalid media type,这是有道理的.

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

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

// "Stra\u00DFe" = "Straße"
static String TINY_UTF8_DOC = "[{ \"id\" : \"2\", \"fields\" : { \"subject\" : [{ \"name\" : \"subject\", \"value\" : \"Stra\u00DFe\" }] } }]";
Run Code Online (Sandbox Code Playgroud)

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

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...
Run Code Online (Sandbox Code Playgroud)

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

  • 有一段时间,这与Mac上的Eclipse相比在Linux上运行.jar时表现不同; 显然这是特定于平台的编码或解码的症状,但我不知道在哪里.具有讽刺意味的是打破了,当我设置Eclipse来对待代码为UTF-8(ASCII对比),我怀疑这是一个重要的线索,但不知道在哪里它适合.
  • 我已经看过时间而不是2个字节,流中有4个字节,虽然这在写入磁盘时可能是一个不同的编码问题,尽管我是专门在文件IO上设置UTF-8
  • 当我查看调试器中的字符串实体时,我看到了字节,但是8位字符是负数.当你运行Two's Compliment数学时,它仍然是正确的Unicode代码点,因此名义上可以,假设httpclient没有错误.

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

编辑:

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

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

非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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*lov 13

看起来问题是如何创建ContentTypeHttpClient StringEntity构造函数的参数.

使用ContentType.APPLICATION_JSON常量作为参数(对应于"application/json; charset = utf-8"mime类型)使一切正常.

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

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());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

{
  "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
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,修好了.看起来constants-vs-strings的版本较新,但我在网上找到的例子比较旧.还要感谢httpbin.org站点的链接,以及读取响应的示例,因为我是这个lib的新手. (2认同)