OkHttp:一个简单的 GET 请求:response.body().string() returns json 内不可读的转义 unicode 符号无法转换为 gson
OkHttp: A simple GET request: response.body().string() returns unreadable escaped unicode symbols inside json can't convert to gson
在 Postman 中发送请求时,我得到以下输出:
{
"valid": false,
"reason": "taken",
"msg": "Username has already been taken",
"desc": "That username has been taken. Please choose another."
}
然而,当使用 okhttp
执行此操作时,我遇到了编码问题,无法使用 gson
将生成的 json 字符串转换为 Java 对象。
我有这个代码:
public static void main(String[] args) throws Exception {
TwitterChecker checker = new TwitterChecker();
TwitterJson twitterJson = checker.checkUsername("dogster");
System.out.println(twitterJson.getValid()); //NPE
System.out.println(twitterJson.getReason());
System.out.println("Done");
}
public TwitterJson checkUsername(String username) throws Exception {
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://twitter.com/users/username_available").newBuilder();
urlBuilder.addQueryParameter("username", username);
String url = urlBuilder.build().toString();
Request request = new Request.Builder()
.url(url)
.addHeader("Content-Type", "application/json; charset=utf-8")
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
Response response = call.execute();
System.out.println(response.body().string());
Gson gson = new Gson();
return gson.fromJson(
response.body().string(), new TypeToken<TwitterJson>() {
}.getType());
}
打印这个:
{"valid":false,"reason":"taken","msg":"\u0414\u0430\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442\u043e","desc":"\u0414\u0430\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442\u043e. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u043e\u0435."}
然后在尝试访问 twitterJson
时抛出 NullPointerException
。调试器将该对象显示为 null
.
TwitterJson:
@Generated("net.hexar.json2pojo")
@SuppressWarnings("unused")
public class TwitterJson {
@Expose
private String desc;
@Expose
private String msg;
@Expose
private String reason;
@Expose
private Boolean valid;
public String getDesc() {
return desc;
}
public String getMsg() {
return msg;
}
public String getReason() {
return reason;
}
public Boolean getValid() {
return valid;
}
...
如何解决 okhttp 的编码问题?
因为响应object只能消费一次。 OKHTTP 在他们的 documentation 中这样说。调用执行后,您将调用响应 object 两次。将 response.body().string() 的结果存储到变量中,然后转换为 GSON.
如果我使用 hello world 示例...
private void testOkHttpClient() {
OkHttpClient httpClient = new OkHttpClient();
try {
Request request = new Request.Builder()
.url("https://www.google.com")
.build();
Call call = httpClient.newCall(request);
Response response = call.execute();
System.out.println("First time " + response.body().string()); // I get the response
System.out.println("Second time " + response.body().string()); // This will be empty
} catch (IOException e) {
e.printStackTrace();
}
}
第二次为空的原因是响应object只能被消费一次。所以你要么
Return 原样响应。不要做 sysOut
System.out.println(response.body().string()); // Instead of doing a sysOut return the value.
或
将响应值存储到 JSON,然后将其转换为 GSON,然后 return 值。
编辑:关于 Unicode 字符。事实证明,由于我所在的位置不是 English-speaking 国家/地区,因此我接受的 json 也不是英文的。我添加了这个 header:
.addHeader("Accept-Language", Locale.US.getLanguage())
请求修复该问题。
在 Postman 中发送请求时,我得到以下输出:
{
"valid": false,
"reason": "taken",
"msg": "Username has already been taken",
"desc": "That username has been taken. Please choose another."
}
然而,当使用 okhttp
执行此操作时,我遇到了编码问题,无法使用 gson
将生成的 json 字符串转换为 Java 对象。
我有这个代码:
public static void main(String[] args) throws Exception {
TwitterChecker checker = new TwitterChecker();
TwitterJson twitterJson = checker.checkUsername("dogster");
System.out.println(twitterJson.getValid()); //NPE
System.out.println(twitterJson.getReason());
System.out.println("Done");
}
public TwitterJson checkUsername(String username) throws Exception {
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://twitter.com/users/username_available").newBuilder();
urlBuilder.addQueryParameter("username", username);
String url = urlBuilder.build().toString();
Request request = new Request.Builder()
.url(url)
.addHeader("Content-Type", "application/json; charset=utf-8")
.build();
OkHttpClient client = new OkHttpClient();
Call call = client.newCall(request);
Response response = call.execute();
System.out.println(response.body().string());
Gson gson = new Gson();
return gson.fromJson(
response.body().string(), new TypeToken<TwitterJson>() {
}.getType());
}
打印这个:
{"valid":false,"reason":"taken","msg":"\u0414\u0430\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442\u043e","desc":"\u0414\u0430\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0443\u0436\u0435 \u0437\u0430\u043d\u044f\u0442\u043e. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u043e\u0435."}
然后在尝试访问 twitterJson
时抛出 NullPointerException
。调试器将该对象显示为 null
.
TwitterJson:
@Generated("net.hexar.json2pojo")
@SuppressWarnings("unused")
public class TwitterJson {
@Expose
private String desc;
@Expose
private String msg;
@Expose
private String reason;
@Expose
private Boolean valid;
public String getDesc() {
return desc;
}
public String getMsg() {
return msg;
}
public String getReason() {
return reason;
}
public Boolean getValid() {
return valid;
}
...
如何解决 okhttp 的编码问题?
因为响应object只能消费一次。 OKHTTP 在他们的 documentation 中这样说。调用执行后,您将调用响应 object 两次。将 response.body().string() 的结果存储到变量中,然后转换为 GSON.
如果我使用 hello world 示例...
private void testOkHttpClient() {
OkHttpClient httpClient = new OkHttpClient();
try {
Request request = new Request.Builder()
.url("https://www.google.com")
.build();
Call call = httpClient.newCall(request);
Response response = call.execute();
System.out.println("First time " + response.body().string()); // I get the response
System.out.println("Second time " + response.body().string()); // This will be empty
} catch (IOException e) {
e.printStackTrace();
}
}
第二次为空的原因是响应object只能被消费一次。所以你要么
Return 原样响应。不要做 sysOut
System.out.println(response.body().string()); // Instead of doing a sysOut return the value.
或
将响应值存储到 JSON,然后将其转换为 GSON,然后 return 值。
编辑:关于 Unicode 字符。事实证明,由于我所在的位置不是 English-speaking 国家/地区,因此我接受的 json 也不是英文的。我添加了这个 header:
.addHeader("Accept-Language", Locale.US.getLanguage())
请求修复该问题。