解析JSON时杰克逊错误"非法字符...只允许常规空格"

rog*_*016 9 java json jackson objectmapper

我试图从URL检索JSON数据,但得到以下错误:

Illegal character ((CTRL-CHAR, code 31)):
only regular white space (\r, \n,\t) is allowed between tokens
Run Code Online (Sandbox Code Playgroud)

我的代码:

final URI uri = new URIBuilder(UrlConstants.SEARCH_URL)
      .addParameter("keywords", searchTerm)
      .addParameter("count", "50")
      .build();
  node = new ObjectMapper().readTree(new URL(uri.toString())); <<<<< THROWS THE ERROR
Run Code Online (Sandbox Code Playgroud)

构建的网址是https://www.example.org/api/search.json?keywords=iphone&count=50

这里出了什么问题?我怎样才能成功解析这些数据?


进口:

import com.google.appengine.repackaged.org.codehaus.jackson.JsonNode;
import com.google.appengine.repackaged.org.codehaus.jackson.map.ObjectMapper;
import com.google.appengine.repackaged.org.codehaus.jackson.node.ArrayNode;
import org.apache.http.client.utils.URIBuilder;
Run Code Online (Sandbox Code Playgroud)

示例响应

{
    meta: {
        indexAllowed: false
    },
    products: {
        products: [ 
            {
                id: 1,
                name: "Apple iPhone 6 16GB 4G LTE GSM Factory Unlocked"
            },
            {
                id: 2,
                name: "Apple iPhone 7 8GB 4G LTE GSM Factory Unlocked"
            }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

Cho*_*ese 11

我遇到了同样的问题,我发现它是由Content-Encoding: gzip标题引起的.客户端应用程序(抛出异常)无法处理此内容编码.客户端应用程序正在使用FWIW io.github.openfeign:feign-core:9.5.0,并且此库似乎在压缩(链接)方面存在一些问题.

您可以尝试将标头添加Accept-Encoding: identity到您的请求中,但是,并非所有Web服务器/ Web应用程序都配置正确,有些人似乎忽略了此标头.有关如何防止gzip压缩内容的详细信息,请参阅此问题.


小智 10

我有一个类似的问题。经过一番研究,我发现 restTemplate 使用了不支持 gzip 编码的 SimpleClientHttpRequestFactory 。要为您的响应启用 gzip 编码,您需要为其余模板对象 - HttpComponentsClientHttpRequestFactory 设置一个新的请求工厂。

restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());


小智 6

我有同样的问题。设置Gzip后就修复了。请参考我的代码

public String sendPostRequest(String req) throws Exception {

    // Create connection
    URL urlObject = new URL(mURL);
    HttpURLConnection connection = (HttpURLConnection) urlObject.openConnection();
    connection.setRequestMethod("POST");
    connection.setRequestProperty("Content-Type", "application/json");
    connection.setRequestProperty("Content-Length", Integer.toString(req.getBytes().length));
    connection.setRequestProperty("Content-Language", "en-US");
    connection.setUseCaches(false);
    connection.setDoOutput(true);

    // Send request
    DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
    wr.writeBytes(req);
    wr.close();

    //Response handling
    InputStream responseBody                = null;
    if (isGzipResponse(connection)) {
        responseBody                = new GZIPInputStream(connection.getInputStream());         
    }else{
        responseBody = connection.getInputStream();
    }
    convertStreamToString(responseBody);

    return response.toString();

}

protected boolean isGzipResponse(HttpURLConnection con) {
    String encodingHeader = con.getHeaderField("Content-Encoding");
    return (encodingHeader != null && encodingHeader.toLowerCase().indexOf("gzip") != -1);
}

public void convertStreamToString(InputStream in) throws Exception {
    if (in != null) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int length = 0;
        while ((length = in.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }

        response = new String(baos.toByteArray());

        baos.close();

    } else {
        response = null;
    }

}
Run Code Online (Sandbox Code Playgroud)


sle*_*ske 5

该消息应该很不言自明:

您正在处理的JSON中存在一个非法字符(在这种情况下为字符代码31,即控制代码“ Unit Separator”)。

换句话说,您接收的数据不是正确的JSON。


背景:

JSON规范(RFC 7159)说:

  1. JSON语法

JSON文本是令牌序列。令牌集包括六个结构字符,字符串,数字和三个文字名称。

[...]

六个结构字符中的任何一个之前或之后都可以使用无意义的空格。

ws = *(

%x20 /; 空间

%x09 /; 水平标签

%x0A /; 换行或换行

%x0D); 回车

换句话说:JSON可能在令牌之间包含空格(“令牌”表示JSON的一部分,即列表,字符串等),但“空格”仅定义为表示空格,制表符,换行符和回车符。

您的文档包含其他内容(代码31),其中仅允许空格,因此不是有效的JSON。


要解析此:

不幸的是,您正在使用的Jackson库没有提供解析此格式错误的数据的方法。要成功解析此内容,您必须先过滤JSON,然后再由Jackson进行处理。

你可能会需要检索(伪)使用REST服务,使用标准的HTTP JSON自己,如java.net.HttpURLConnection中。然后适当地过滤掉“坏”字符,并将结果字符串传递给Jackson。如何执行此操作完全取决于您使用Jackson的方式。

如果您遇到问题,请随时提出其他问题:-)。