博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android开发之最流行的网络框架Retrofit - jsonp及特殊响应数据格式处理
阅读量:6812 次
发布时间:2019-06-26

本文共 4251 字,大约阅读时间需要 14 分钟。

什么是jsonp

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决浏览器的跨域数据访问的问题。返回数据格式如:

jsonp1382016430883([{"id":1,"title":"XXXX"},{"id":2,"title":"YYYYY"}])

jsonpCallback({"code":200,"data":[{"id":1,"title":"XXXX"},{"id":2,"title":"YYYYY"}]})

可以看出jsonp和json格式仅仅只是在收尾加了"()"和特殊字符串。我们暂且不管jsonp的概念,今天我要讲的是使用Retrofit请求服务端接口返回的是jsonp格式如何处理问题。

问题引出

我们都知道服务端接口返回数据一般是json/xml/text/html等,而我们现有的数据解析库有pull/sax/gson/fastjson等,用的最多的是gson,但是gson是不支持jsonp格式的,这就需要我们在gson解析返回数据之前做处理,即把非json的数据格式处理成标准的json格式。

解决方案

既然我们要在gson解析响应数据之前处理响应数据,首先会想到Retrofit中的拦截器(Interceptor),当然其实这个部分是属于okhttp的,而我们的项目中用的是Retrofit网络框架自然就离不开okhttp相关的api。 其实有两种方案,一个是利用okhttp的Interceptor这个类在响应之前将数据处理好再交给gson处理,另一个是利用Retrofit的Converter.Factory这个类进行数据转换。

方案一

自定义拦截器(Interceptor),在拦截器里对ResponseBody做处理。这个方法比较挫,但是兼容性很好,比较灵活,适用不同的服务端接口返回数据,比如既有json又有jsonp等。

import java.io.IOException;import okhttp3.Interceptor;import okhttp3.MediaType;import okhttp3.Response;import okhttp3.ResponseBody;public class JsonpHandleInterceptor implements Interceptor {    @Override    public Response intercept(Chain chain) throws IOException {        Response response = chain.proceed(chain.request());        ResponseBody responseBody = response.body();        MediaType mediaType = responseBody.contentType();        String content = responseBody.string();        int index = content.indexOf("(");        if (/*content.startsWith("jsonp") &&*/ index != -1) {            content = content.substring(index + 1, content.length() - 1);        }        return response.newBuilder()                .body(ResponseBody.create(mediaType, content))                .build();    }}复制代码

为okhttp添加拦截器并且设置给Retrofit

OkHttpClient httpClient = new OkHttpClient.Builder()                .addInterceptor(new JsonpHandleInterceptor())                .build(); Retrofit retrofit = new Retrofit.Builder()                .baseUrl("http://juejin.im")                .client(httpClient)                .build();复制代码

方案二

自定义Converter.Factory

import android.support.annotation.Nullable;import com.google.gson.Gson;import com.google.gson.TypeAdapter;import com.google.gson.reflect.TypeToken;import java.lang.annotation.Annotation;import java.lang.reflect.Type;import okhttp3.ResponseBody;import retrofit2.Converter;import retrofit2.Retrofit;public class GsonJsonpConverterFactory extends Converter.Factory {    private final Gson gson;    public static GsonJsonpConverterFactory create() {        return create(new Gson());    }    public static GsonJsonpConverterFactory create(Gson gson) {        if (gson == null) {            throw new NullPointerException("gson == null");        }        return new GsonJsonpConverterFactory(gson);    }    private GsonJsonpConverterFactory(Gson gson) {        this.gson = gson;    }    @Nullable    @Override    public Converter
responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter
adapter = gson.getAdapter(TypeToken.get(type)); return new GsonJsonpResponseBodyConverter<>(gson, adapter); }}复制代码

自定义Converter

import com.google.gson.Gson;import com.google.gson.TypeAdapter;import com.google.gson.stream.JsonReader;import java.io.IOException;import java.io.Reader;import okhttp3.ResponseBody;import retrofit2.Converter;public final class GsonJsonpResponseBodyConverter
implements Converter
{ private final Gson gson; private final TypeAdapter
adapter; GsonJsonpResponseBodyConverter(Gson gson, TypeAdapter
adapter) { this.gson = gson; this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOException { Reader reader = value.charStream(); int item = reader.read(); while (item != '(' && item != -1) { item = reader.read(); } JsonReader jsonReader = gson.newJsonReader(reader); try { return adapter.read(jsonReader); } finally { reader.close(); } }}复制代码

配置Retrofit

Retrofit retrofit = new Retrofit.Builder()                .baseUrl(baseUrl)                .client(httpClient)                .addConverterFactory(GsonJsonpConverterFactory.create())                .build();复制代码

总结

需要参考GsonConverterFactory部分源码。

转载地址:http://etzzl.baihongyu.com/

你可能感兴趣的文章
【Java每日一题】20161214
查看>>
requireJs 模块化简陋版本
查看>>
我的友情链接
查看>>
How to upgrade vim to version 8 on CentOS 7
查看>>
xcode pod 报import 找不到 pods的支持问题解决方法之一
查看>>
nginx配置让任何文件在浏览器中显示文本text/plain
查看>>
思科路由器×××配置-- 动态 site-to-site ×××(上)
查看>>
centos小常识
查看>>
PHP遍历文件夹函数-listfile
查看>>
解决ntp的错误 no server suitable for synchronization found
查看>>
RHEL6.5下部署samba企业级文件服务器实战
查看>>
React 深入系列1:React 中的元素、组件、实例和节点
查看>>
2015开篇——配置nginx URL有感
查看>>
Dockerfile基于Centos7安装nginx容器
查看>>
让wordpress支持中文用户名的简便方法
查看>>
Go编程笔记(12)
查看>>
多网卡bond0
查看>>
Zend API: config.m4配置文件的一些宏
查看>>
如何判断Linux系统是多少位的
查看>>
测试你的Python 水平----3
查看>>