Spring returns 在 POST 中使用重音字符时为 400

Spring returns 400 when using accented character in POST

问题:

当从 Android 应用程序发送 POST 请求时,重音字符导致 Jackson 在对象映射阶段失败,但在 chrome 使用 Advanced Rest Client 插件时工作正常.

这让我相信问题与 Android 代码发送请求的方式有关,但我尝试添加对 UTF-8 的显式引用但没有成功。当我在执行过程中调试过程时,所有值似乎都是正确的。

上下文:

我正在 Android 上开发一个应用程序,该应用程序连接到公开 Spring 中实现的端点的服务器。服务器使用 Spring MVC 开发并使用 Google App Engine。

特定端点可以接收用户输入的值,其中可能包含重音字符。

有效负载遵循此结构,映射到服务器端的对象:

{
    "senderEmail":"<email here>",
    "token":"<token here>",
    "friendList":["<email here>"],
    "base64Value":"<base64 encoded value here>",
    "message":"ú"
}

当从 REST 客户端发送此有效负载时,服务器会很好地处理请求并且 returns 一个 200。当从 Android 应用程序发送它时,会抛出以下异常:

org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver resolveException: Resolving exception from handler [public org.springframework.http.ResponseEntity<java.lang.Object> com.web.controllers.PictureController.postPic(com.web.controllers.viewobjects.PostPicRequest)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Invalid UTF-8 middle byte 0x22
     at [Source: com.google.apphosting.runtime.jetty.RpcConnection$RpcRequestInput@832f7f; line: 1, column: 15] (through reference chain: com.web.controllers.viewobjects.PostPicRequest["message"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 middle byte 0x22
     at [Source: com.google.apphosting.runtime.jetty.RpcConnection$RpcRequestInput@832f7f; line: 1, column: 15] (through reference chain: com.web.controllers.viewobjects.PostPicRequest["message"])

代码:

发送请求的 Android 代码(为 public 查看而编辑):

URL url = new URL( URL_POST );
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Accept-Encoding", ""); 

String base64Value = "blabla"

//Get JSON
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate(Api.POST_PARAM_BASE64VALUE, base64Value);
jsonObject.accumulate(Api.POST_PARAM_SENDEREMAIL, senderEmail);
jsonObject.accumulate(Api.POST_PARAM_TOKEN, token);
jsonObject.accumulate(Api.POST_PARAM_MESSAGE, message);

//Make array from friends string
String[] allFriendsArray = friendList.split(",");
JSONArray friendsJsonArray = new JSONArray();
for(String x : allFriendsArray) {
    friendsJsonArray.put(x.trim());
}

jsonObject.accumulate(Api.POST_PARAM_FRIENDLIST, friendsJsonArray);
jsonObject.accumulate(Api.POST_PARAM_ISANONYMOUS, isAnonymous);

DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();

int httpResponseCode = urlConnection.getResponseCode();

在 Android 中使用以下代码时得到相同的响应:

HttpPost httpPost = new HttpPost(Api.URL_POST);
httpPost.setEntity(new StringEntity(jsonObject.toString()));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = new DefaultHttpClient().execute(httpPost);    

Spring 方法定义,它包含在一个用@RestController 注释的控制器中:

@RequestMapping(value= "/post", method = RequestMethod.POST)
public ResponseEntity<Object> post(@RequestBody PostRequest postRequest) { /*code here*/}

找到以下代码片段 (here),它正确地编码了有效负载,并且在服务器端也被正确接收。

谢谢大家!

    OutputStream os = urlConnection.getOutputStream();
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
    writer.write( jsonObject.toString() );
    writer.close();
    os.close();
    int httpResponseCode = urlConnection.getResponseCode();