【问题标题】:Retrofit - getting null error response body (MalformedJsonException)改造 - 获取空错误响应正文(MalformedJsonException)
【发布时间】:2015-05-21 01:10:41
【问题描述】:

我试图在onFailure(RetrofitError error) 中获取错误响应正文,但得到null

我将标题 Accept: text/plain 用于请求,并从响应中收到 Content-Type: text/plain,如果我设置 LogLevel.FULL,则可以将正文视为文本。此外,error.getResponse().getStatus() 给了我正确的状态码。

但是当我执行error.getBody()error.getResponse.getBody() 时,它会返回null。在error 内部,我看到successTypejava.lang.String,所以我认为它应该给我String,但error.getCause() 显示给我

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException:使用 JsonReader.setLenient(true) 在第 1 行列接受格式错误的 JSON 6 路径 $

另外,error.getKind()CONVERSION,代表

/** 在(反)序列化主体时引发异常。 */

但我希望得到像HTTP这样的善意

问题是为什么当所有标头都使用text/plainsuccessTypeString 时它会尝试转换为JSON? 我需要以纯文本形式获得回复。

代码sn-p:

RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(url)
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .setClient(new CustomOkHttpClient())
        .setRequestInterceptor(new TransactionsRequestInterceptor())
        .build();

TransactionsRestClient httpClient = restAdapter.create(TransactionsRestClient.class);
httpClient.createNewTransaction(request, new retrofit.Callback<String>() {
    @Override
    public void success(String transactionId, Response response) {

    }

    @Override
    public void failure(RetrofitError error) {
        // error.getBody() is null
    }
}
public interface TransactionsRestClient {
    @POST("/transactions")
    void createNewTransaction(@Body TransactionRequest request, Callback<String> transactionId);
}

public class TransactionsRequestInterceptor implements RequestInterceptor {
    @Override
    public void intercept(RequestFacade request) {
        request.addHeader(HOST, host);
        request.addHeader(TOKEN, token);
        request.addHeader(ACCEPT, TEXT);
        request.addHeader(CONTENT_TYPE, JSON);
    }

记录的请求/响应:

 ---> HTTP POST $url
Host: $host
Accept: text/plain
Content-Type: application/json
Content-Length: 133
$request_body
---> END HTTP (133-byte body)

<--- HTTP 202 $url //202 is expected
Access-Control-Allow-Origin:
Content-Type: text/plain
Date: Wed, 20 May 2015 16:08:46 GMT
Server: spray-can/1.3.1
Content-Length: 50
Connection: keep-alive
OkHttp-Selected-Protocol: http/1.1
OkHttp-Sent-Millis: 1432138139875
OkHttp-Received-Millis: 1432138140004
The record for test10 is not currently authorized. // this is body I have to get
<--- END HTTP (50-byte body)

谢谢。

【问题讨论】:

  • 因为 Retrofit 是 REST client 并且期望响应是 JSON 而不是纯文本。您的回复似乎已返回为 null 这不是 JSON
  • REST 也支持纯文本,而不仅仅是 json。在对改造请求/响应进行全级别日志记录时可以看到响应并在此处显示为文本,但无法访问
  • 请张贴您用于提出请求的相关代码
  • 您应该发布您的 Android 代码,这是您的问题(和解决方案)的根源。请不要在外部资源中发布代码,因为它们可能会过期

标签: android retrofit


【解决方案1】:

默认情况下,Retrofit 将响应读取为 JSON 并自动解析它。你必须改变它的默认行为。

This blog post 可能会有所帮助,并建议您将字符串响应设为:

new String(((TypedByteArray) response.getBody()).getBytes());

【讨论】:

  • 无论如何,请发布您的相关代码,以便我们在您遇到转换器问题时提供帮助
  • 此示例适用于 Response 实例,但我正在努力处理 RetrofitError 实例。只是给我error.getBoy() 为空,所以任何进一步的转换和获取字节都会抛出 NPE
  • 您收到错误是因为 Retrofits 假设您收到 JSON 响应并在尝试转换时抛出错误。您不得隐瞒此响应,这是博文所说的,但并未解释如何避免使用 GSON。请发布您的相关代码
  • @ViMatviichuk 您的响应不是有效的 json,您应该遵循上面的建议。
  • 我的回复是文本,而不是 json。我想把它作为字符串,而不是JsonElement。服务器返回文本,我需要获取文本,但不是 json。 REST 不仅仅是关于 json,它支持所有 HTTP 内容格式,如纯文本、json、xml、任何其他自定义类型等。在我的情况下,我只需要文本
【解决方案2】:

在您的代码 new RestAdapter.Builder() 中,您没有指定转换器 (setConverter())。

查看改造代码,更具体地说是 RestAdapterPlatform 我检查了如果您不指定转换器,它将默认使用 GSON:

@Override Converter defaultConverter() {
  return new GsonConverter(new Gson());
}

我相信解决方案是创建一个自定义转换器(扩展转换器类)并且对您的响应不做任何事情,只返回原始字符串。

Here 是一个关于如何创建自己的转换器的示例。

【讨论】:

  • 这将改变我的请求转换器,而我的请求必须保持 json。我需要发送 json 并获取文本。在这种情况下自定义转换器将不起作用,因为请求序列化将失败。我假设改造使用基于 http 标头的正文解析器,但我的标头是 text/plain 并且仍然得到 json 异常
  • 这是您回复的转换器
  • 我的成功响应是 json 格式,这是正确的,但我的失败响应是纯文本格式的。无论如何,我使用了 StringConverter 并得到了 http-400(错误请求)
  • 如果您解决了问题,请在此处发帖告知我们
  • 作为解决方案,我们将所有后端服务切换为 json。如何从错误正文中获取文本,但不是 json - 仍然不知道。稍后查看改造的源代码,然后发布答案
猜你喜欢
  • 1970-01-01
  • 2017-04-19
  • 2012-05-10
  • 2016-11-17
  • 1970-01-01
  • 2018-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多