okhttp 3.4.2 攔截器使用總結
阿新 • • 發佈:2019-01-11
okhttp攔截器作為它的重要一員,如果好好利用往往能使我們事半功倍,先看一下攔截器的核心介面Interceptor
:
public interface Interceptor {
Response intercept(Chain chain) throws IOException;
interface Chain {
Request request();
Response proceed(Request request) throws IOException;
Connection connection();
}
}
要實現攔截,就要定義類實現介面Interceptor
intercept
,該方法接收引數Chain
,返回Response
,在該方法中實現自己的攔截邏輯。
下面簡單總結一下intercept
方法中可以實現的功能:
實現介面
在開始之前,我們先定義LoggingInterceptor
實現介面Interceptor
,其中的變數和方法後面會用到:
public final class LoggingInterceptor implements Interceptor {
private static final Charset UTF8 = Charset.forName("UTF-8");
public static final String HTTP_HEADER = "<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">";
public static final String HTTP_TAIL = "</string>";
private boolean isPlaintext(Buffer buffer) {
try {
Buffer prefix = new Buffer();
long byteCount = buffer.size() < 64 ? buffer.size() : 64;
buffer.copyTo(prefix, 0, byteCount);
for (int i = 0; i < 16; i++) {
if (prefix.exhausted()) {
break;
}
int codePoint = prefix.readUtf8CodePoint();
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
return false;
}
}
return true;
} catch (EOFException e) {
return false; // Truncated UTF-8 sequence.
}
}
private boolean bodyEncoded(Headers headers) {
String contentEncoding = headers.get("Content-Encoding");
return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
}
private String protocol(Protocol protocol) {
return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1";
}
}
列印請求
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
Connection connection = chain.connection();
Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
String requestStartMessage =
"--> " + request.method() + ' ' + request.url() + ' ' + protocol(protocol);
//請求方法及url等
logger.log(requestStartMessage);
logger.log("---請求頭---");
Headers headers = request.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
logger.log(headers.name(i) + ": " + headers.value(i));
}
logger.log("---請求引數---");
HttpUrl url = request.url();
for (String name : url.queryParameterNames()) {
StringBuffer sb = new StringBuffer();
sb.append(url.queryParameterValues(name));
//去除頭尾多餘的"[]"
sb.deleteCharAt(sb.length() - 1);
sb.deleteCharAt(0);
logger.log(name + ": " + sb);
}
logger.log("---請求體---");
if (hasRequestBody && !bodyEncoded(headers)) {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
Charset charset = UTF8;
MediaType contentType = requestBody.contentType();
if (contentType != null) {
charset = contentType.charset(UTF8);
}
if (isPlaintext(buffer)) {
logger.log(buffer.readString(charset).replaceAll("&", "\n"));
}
}
//請求結束
logger.log("");
logger.log("--> END Request");
logger.log("");
return chain.proceed(request);
}
修改請求
修改請求頭
@Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.method(original.method(), original.body());
Headers.Builder header = new Headers.Builder();
header.add("os", "android");
header.add("version", "1.2.5");
Request request = requestBuilder.headers(header.build()).build();
return chain.proceed(request);
}
修改請求體
這種修改只針對以下的需求:
- 得到原始的請求體字串,如
{"name":"Sbingo","job":"android developer"}
- 在字串中新增
secret
Key/Value對,得到{"name":"Sbingo","job":"android developer","secret":"F910EUY09"}
- 在字串前後新增標籤
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{"name":"Sbingo","job":"android developer","secret":"F910EUY09"}</string>
- 使用上一步得到的字串作為請求體
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request newRequest;
if (originalRequest.body() instanceof FormBody) {
Request.Builder requestBuilder = originalRequest.newBuilder();
StringBuilder jsonRequest = new StringBuilder();
jsonRequest.append("{");
FormBody oldFormBody = (FormBody) originalRequest.body();
for (int i = 0; i < oldFormBody.size(); i++) {
String name = oldFormBody.encodedName(i);
String value = oldFormBody.encodedValue(i);
jsonRequest.append("\"");
jsonRequest.append(name);
jsonRequest.append("\":\"");
jsonRequest.append(value);
jsonRequest.append("\"");
jsonRequest.append(",");
}
jsonRequest.append("\"secret\":\"");
jsonRequest.append("F910EUY09");
jsonRequest.append("\"");
jsonRequest.append("}");
String request = HTTP_HEADER + jsonRequest.toString() + HTTP_TAIL;
MediaType mediaType = MediaType.parse("text/xml; charset=utf-8");
newRequest = requestBuilder.post(RequestBody.create(mediaType, request)).build();
} else {
throw new RuntimeException("請使用表單提交網路請求!");
}
return chain.proceed(newRequest);
}
列印響應
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startNs = System.nanoTime();
Response response = chain.proceed(request);
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
ResponseBody responseBody = response.body();
//響應碼及url等
logger.log("<-- "
+ response.code()
+ ' '
+ response.message()
+ ' '
+ response.request().url()
+ " ("
+ tookMs
+ "ms"
+ ')');
logger.log("---響應頭---");
Headers responseHeaders = response.headers();
for (int i = 0, count = responseHeaders.size(); i < count; i++) {
logger.log(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
logger.log("---響應體---");
if (HttpHeaders.hasBody(response) && !bodyEncoded(responseHeaders)) {
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE);
Buffer responseBuffer = source.buffer();
Charset responseCharset = UTF8;
MediaType responseContentType = responseBody.contentType();
if (responseContentType != null) {
responseCharset = responseContentType.charset(UTF8);
}
if (isPlaintext(responseBuffer)) {
com.orhanobut.logger.Logger.json(responseBuffer.clone().readString(responseCharset));
}
}
logger.log("");
logger.log("<-- END Response");
return response;
}