Android上的google-api-java-client JSON解析器在GAE上生成空的self.request.body

2 投票
1 回答
690 浏览
提问于 2025-04-16 10:47

这段内容和另一个关于网址缩短器的问题有关。网址缩短器的代码在独立的Java环境和Android上都能正常工作。但是,当把这段代码用在一个自定义的Google App Engine应用时,独立Java环境下运行没问题,但在Android上却出现了一个空的self.request.body。这是为什么呢?

要复现这个问题,可以在Android上运行下面的代码,先用Google的缩短网址:https://www.googleapis.com/urlshortener/v1/url,再用一个自定义的网址去访问一个网络服务器。 在独立的Java环境中,这段代码在这两种情况下都会产生完全相同的请求(这很正常)。但在Android上,使用自定义网址时,内容体是空的,而且内容长度没有设置。 我使用的是google-api-java-client 1.2.2-alpha版本,和jackson 1.7.1版本。

代码片段如下:

    HttpTransport transport = GoogleTransport.create();
    HttpRequest request = transport.buildPostRequest();

    // Change this URL below from Google Shortener URL, to a custom URL,
    // and the code on Android produces an empty body and Content-Length is not set
    request.setUrl("GoogleAppEngine url goes here");

    JsonCContent content = new JsonCContent();
    GenericData data = new GenericData();
    data.put("id", "whatever");
    content.data = data;
    request.content = content;
    HttpResponse response = request.execute();

1 个回答

2

我做了一些调试,结果是这样的:

  • 在Android上,默认情况下,它会选择Apache HTTP客户端来处理底层的网络传输。这个代码非常简单,看起来没有正确设置请求的Content-Type和Content-Length。请求是发出去的,但一些(大多数)比较挑剔的网络服务器会跳过请求的主体。谷歌的网络服务器似乎处理得还不错。所以,对于谷歌的服务器来说,这样是可以的,但对于其他网络服务器就不一定了(这有点奇怪,但这不是我问题的重点)。

  • 而在Java中,默认选择的是java.net.HttpURLConnection来处理底层的HTTP传输。这个实现比较详细,会把所有需要的字段都设置好。Content-Length、Content-Type以及其他所有字段都有。JSON内容会被序列化,所有的网络服务器都能正常工作,包括我自己的GAE应用。

所以,在Android上,以下的解决方法可以解决这个问题:

在你执行请求之前,放入以下调用:

HttpTransport.setLowLevelHttpTransport(new com.google.api.client.javanet.NetHttpTransport());

这样一来,在Android上,你就会使用那个实际上能正常工作的传输方式(请求会更整洁)。

补充一下,生活中常常会这样,我有点懒,问了这个问题,希望有人能帮我解决。结果我自己调试并解决了这个问题,还得写下这些内容。虽然多了点工作,但我想这对其他人会有帮助。希望大家能觉得有用。

另外,google api java客户端现在真不错 ;) 感谢作者们的辛勤付出。

撰写回答