一、通过官方文档对Interceptor的介绍,我们可以得知Interceptor主要功能有两个:
1,重写请求:可以添加、移除、替换请求头。也可以改造只有一个请求体的请求的请求体(这句话有点拗口),例如你可以添加一个用于压缩请求体的应用拦截器,前提是你的web服务器支持请求体的压缩;
2,重写响应:可以重写响应头并转换响应体。这通常比重写请求头更危险,因为它可能违反了web服务器的期望。如果您处于棘手的情况并准备应对后果,重写响应标头是解决问题的有效方法。例如,您可以修复服务器配置错误的Cache-Control响应头,以实现更好的响应缓存
一般来说我们重写请求的情况会比较多一点,先看看官方是如何实现Interceptor的:
第一个是一个简单的输出请求及响应日志的Interceptor
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
实现interceptor我们可以通过Request request = chain.request();获取原始的请求Request对象,这里我们可以理解为Okhttp将原始的请求拦截了,这样就可以输出原始的请求地址,请求头等信息。然后调用chain.proceed(request),再将原始请求发送出去,并获取响应结果Resonse response,这里我们可以理解为将拦截的请求重新发送出去!有了resonse对象自然我们就可以输出和响应结果相关的信息。
第二个例子是压缩请求体的一个拦截器(这里官方反复强调服务端一定要支持请求体压缩,否则服务端可能无法解析请求体)
/** This interceptor compresses the HTTP request body. Many webservers can't handle this! */
final class GzipRequestInterceptor implements Interceptor {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request originalRequest = chain.request();
if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
return chain.proceed(originalRequest);
}
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.method(originalRequest.method(), gzip(originalRequest.body()))
.build();
return chain.proceed(compressedRequest);
}
private RequestBody gzip(final RequestBody body) {
return new RequestBody() {
@Override
public MediaType contentType() {
return body.contentType();
}
@Override
public long contentLength() {
return -1; // We don't know the compressed length in advance!
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
body.writeTo(gzipSink);
gzipSink.close();
}
};
}
}
同样的也是先获取原始请求Request originalRequest = chain.request();然后在通过原始请求构造新的请求对象
Request compressedRequest = originalRequest.newBuilder()
.header("Content-Encoding", "gzip")
.method(originalRequest.method(), gzip(originalRequest.body()))
.build();
新的请求对象的请求体是对原始的请求体的压缩gzip(originalRequest.body())
最后在将新的请求compressedRequest发送到服务端。
二、那么我们就可以依葫芦画瓢自己动手实现一个添加SessionId请求头的Interceptor直接贴上代码
public class SimpleHeaderInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
if (!TextUtils.isEmpty(Utils.getSessionId())){
return chain.proceed(originalRequest);
}
Request newRequest = originalRequest.newBuilder()
.header("SessionId", Utils.getSessionId())
.build();
Response response = chain.proceed(newRequest);
return response;
}
}
三、我们还可以修改请求体,下面别人的修改请求体的例子,功能是给post请求添加一个token参数
/**
* Created by debanjan on 16/4/17.
*/
public class TokenInterceptor implements Interceptor {
public TokenInterceptor(Context context) {
this.context = context;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RequestBody requestBody = request.body();
String token = "toku";//根据需求传入你的token.
String subtype = requestBody.contentType().subtype();
if(subtype.contains("json")){
requestBody = processApplicationJsonRequestBody(requestBody, token);
}
else if(subtype.contains("form")){
requestBody = processFormDataRequestBody(requestBody, token);
}
if(requestBody != null) {
Request.Builder requestBuilder = request.newBuilder();
request = requestBuilder
.post(requestBody)
.build();
}
return chain.proceed(request);
}
private String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
private RequestBody processApplicationJsonRequestBody(RequestBody requestBody,String token){
String customReq = bodyToString(requestBody);
try {
JSONObject obj = new JSONObject(customReq);
obj.put("token", token);
return RequestBody.create(requestBody.contentType(), obj.toString());
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
private RequestBody processFormDataRequestBody(RequestBody requestBody, String token){
RequestBody formBody = new FormBody.Builder()
.add("token", token)
.build();
String postBodyString = bodyToString(requestBody);
postBodyString += ((postBodyString.length() > 0) ? "&" : "") + bodyToString(formBody);
return RequestBody.create(requestBody.contentType(), postBodyString);
}
}