Java 杰克逊->;杰克逊&x2B;HttpPost=";无效的UTF-8中间字节“;,设置Mime和编码
我在客户端中使用ApacheHTTP客户端libs和Jackson。当我将JSON发布到服务器时,会出现以下错误:Java 杰克逊->;杰克逊&x2B;HttpPost=";无效的UTF-8中间字节“;,设置Mime和编码,java,json,utf-8,jackson,Java,Json,Utf 8,Jackson,我在客户端中使用ApacheHTTP客户端libs和Jackson。当我将JSON发布到服务器时,会出现以下错误: org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0x65 at [Source: HttpInputOverHTTP@22a4ac95; line: 1, column: 81] 如果我没有设置任何标题,我会得到无效的媒体类型,这很有意义 如果我使用curl和相同的头文件,服务器会接受它,所以
org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0x65
at [Source: HttpInputOverHTTP@22a4ac95; line: 1, column: 81]
如果我没有设置任何标题,我会得到无效的媒体类型
,这很有意义
如果我使用curl和相同的头文件,服务器会接受它,所以我认为服务器还可以(只是巧合,它也使用了Jackson)
这就是文件;我将其硬编码为Java文本,仅使用8位字符,以避免任何其他地方发生损坏
// "Stra\u00DFe" = "Straße"
static String TINY_UTF8_DOC = "[{ \"id\" : \"2\", \"fields\" : { \"subject\" : [{ \"name\" : \"subject\", \"value\" : \"Stra\u00DFe\" }] } }]";
以下是我一直在使用的代码,以及各种尝试的注释:
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...
我注意到的其他奇怪的事情:
- 有一段时间,这在Mac上的Eclipse上表现不同于在Linux上运行.jar;显然,这是特定于平台的编码或解码的症状,但我不知道在哪里。具有讽刺意味的是,当我将Eclipse设置为将代码视为UTF-8(相对于ASCII)时,我怀疑这是一条重要的线索,但不确定它适用于何处
- 我见过流中有4个字节而不是2个字节的情况,尽管在写入磁盘时这可能是一个不同的编码问题,尽管我在文件IO上专门设置了UTF-8
- 当我在调试器中查看字符串实体时,我看到了字节,但8位字符是负数。当您完成这两个恭维的数学运算时,它仍然是正确的Unicode代码点,所以名义上是可以的,假设httpclient没有bug
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 );
}
}
curl在发布到服务器时工作,但是我不能共享服务器代码。有人指出,由于curl不是用Java编写的,因此它的行为可能有所不同,因此服务器代码仍然可能是可疑的
因此,作为进一步的测试,下面的代码不使用ApacheHttpClient库,并且在发布到服务器时可以工作。这证明了服务器是好的,我在客户端使用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 );
}
}
问题似乎在于如何创建HttpClient的
StringEntity
构造函数的ContentType
参数
使用ContentType.APPLICATION\u 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());
}
}
输出:
{
"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
这对我很有用:(将“UTF-8”指定给StringEntity)
这里有个问题;这里,
ß
是作为转义UTF-16序列的\u00DF
,但您读取字节0x65;您的来源是什么?只有当您试图读取非UTF-8的UTF-8时,才会产生UTF-8错误。UTF-8的工作原理是在高位侧用1填充第一个字节,以指示要为字符读取多少字节。其余的字节必须以“10”开头,这有点像校验位,否则它知道解析有问题。在本例中,您有一个左侧有1的字节,但后面没有足够的字节来满足指定的数字。长话短说,我猜你的客户根本没有发送UTF-8。参考:你能试着在u00DF
之前将反斜杠加倍,这样JSON就会显示“\u00DF”@CodeChimp谢谢,我同意它在到达服务器时是错误编码的,但问题是如何/为什么?显然,我在某种程度上错误地使用了客户端libs,但我看到的所有示例似乎都遵循这些模式。@对于您的第一条注释,反斜杠u和4位数字是Java中引用未编码代码点的标准方式,您通常不会使用\uDF(2位)。据我所知,在RAM中,Java使用UTF-16(或某种变体)作为字符,只有在文件或其他进程之间进行流传输时,才会转换为UTF-8。谢谢,这就解决了这个问题。看起来常量vs字符串的版本更新了,但我在网上找到的示例更旧。还感谢您提供了到httpbin.org网站的链接,以及阅读响应的示例,因为我是这个库的新手。我尝试使用ContentType.APPLICATION_JSON
2nd arg创建StringEntity。。。或者向HttpPost对象添加一个头,如下面的request.addHeader(“Content-Type”,ContentType.APPLICATION_JSON.toString())代码>。但是,当我的消息包含例如“é”、“è”或“ô”时,我不断收到相同的错误“JsonMappingException:Invalid UTF-8 middle byte 0xZZ”。。。ZZ是一个十六进制值,根据值的不同而变化。