前言
怎麼說呢,幾個月沒寫部落格,時過境遷,也斷了那種感覺。一個好的習慣需要27天的週期才能養成,要放棄一個習慣那不需要週期,懶就可以。主要也沒有好的內容要向廣大基友來傳播,這也省了大家的閱讀時間 去刷抖音了hhhh,不說了 進入主題
騷操作目錄
也就不廢話了,可以看到下面的目錄,有哪些騷操作 ,希望可以幫助日常開發中的小夥伴們。
- URL重定向
- 請求體資料加密
- HEAD動態新增
- 請求日誌抓取
URL重定向
如何重定向,說白了就是更換個新的url,但是一般服務端做比較好,客戶端就顯得有些雞肋。但是這個東西日常也會有用到,比如一些場景,測試生成環境的切換。業務多了,幾個人混合開發的後臺,每個人的程式碼不同意導致了baseurl還不同,這時候可以通過一個入口來修改就行,不然每個地方都去修改,介面量大的話會很麻煩。
- 自定義一個Interceptor(TestInterceptor後面都是基於這個來講解),直接建立個類實現Interceptor介面即可,然後在Okhttp初始化的是新增這個攔截器即可
public class TestInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
return null;
}
}
複製程式碼
然後在你需要初始化的okhttp的地方新增這個攔截器
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OkHttpClient build = new OkHttpClient.Builder()
.addInterceptor(new TestInterceptor())
.build();
}
}
複製程式碼
那麼接下來我們需要幹什麼呢,攔截器已經寫好了,既然定義是攔截器,肯定請求體資訊都在那裡。我們可以在介面Interceptor裡面的方法intercept給了我們一個引數Chain,一切的源頭都在這裡面。來看看接下來如何進行騷操作來改變初始的URL達到重定向的功能
public class TestInterceptor implements Interceptor {
private String newHost = "127.0.0.1";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url();
//http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
String scheme = url.scheme();// http https
String host = url.host();// 127.0.0.1
String path = url.encodedPath();// /test/upload/img
String query = url.encodedQuery();// userName=xiaoming&userPassword=12345
StringBuffer sb = new StringBuffer();
String newUrl = sb.append(scheme).append(newHost).append(path).append("?").append(query).toString();
Request.Builder builder = request.newBuilder()
.url(newUrl);
return chain.proceed(builder.build());
}
}
複製程式碼
上面只是簡單的換了一下host retrofit可以輕易做到,在構造retrofit的時候可以修改baseUrl,但是如果要換path呢,這時候可能retrofit不是那麼好做,而且你需要每個地方都要換,這時候你可以在這裡當成一個統一的入口new一個新的path即可。簡單吧,對於後面的每個欄位說明意思我在後面也有備註,可以看到拆分後的樣子
請求體資料加密
既然要對請求體加密,那肯定要知道請求體在哪裡,然後才能加密,其實都一樣不論是加密url裡面的query內容還是加密body體裡面的都一樣,只要拿到了對應的資料我們想怎麼做怎麼,有的介面比較奇葩,他需要根據請求體的內容進行簽名認證。不論如何我們拿到了請求體當然想怎麼樣就怎麼樣,看下嘛的操作
- 加密query內容
public class TestInterceptor implements Interceptor {
private String newHost = "127.0.0.1";
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url();
//http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
String scheme = url.scheme();// http https
String host = url.host();// 127.0.0.1
String path = url.encodedPath();// /test/upload/img
String query = url.encodedQuery();// userName=xiaoming&userPassword=12345
StringBuffer sb = new StringBuffer();
sb.append(scheme).append(newHost).append(path).append("?");
Set<String> queryList = url.queryParameterNames();
Iterator<String> iterator = queryList.iterator();
for (int i = 0; i < queryList.size(); i++) {
String queryName = iterator.next();
sb.append(queryName).append("=");
String queryKey = url.queryParameter(queryName);
//對query的key進行加密
sb.append(CommonUtils.getMD5(queryKey));
if (iterator.hasNext()) {
sb.append("&");
}
}
String newUrl = sb.toString();
Request.Builder builder = request.newBuilder()
.url(newUrl);
return chain.proceed(builder.build());
}
}
複製程式碼
這樣拼接的query內容就可以直接統一加密了。我這裡只是簡單的md5加密 如果說服務端和客戶端定義了一套加密解密協議,就可以在這裡進行特定的加密方式進行加密
- 加密body體內容
public class TestInterceptor implements Interceptor {
private String newHost = "127.0.0.1";
public static String requestBodyToString(RequestBody requestBody) throws IOException {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
return buffer.readUtf8();
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url();
//http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
String scheme = url.scheme();// http https
String host = url.host();// 127.0.0.1
String path = url.encodedPath();// /test/upload/img
String query = url.encodedQuery();// userName=xiaoming&userPassword=12345
StringBuffer sb = new StringBuffer();
sb.append(scheme).append(newHost).append(path).append("?");
Set<String> queryList = url.queryParameterNames();
Iterator<String> iterator = queryList.iterator();
for (int i = 0; i < queryList.size(); i++) {
String queryName = iterator.next();
sb.append(queryName).append("=");
String queryKey = url.queryParameter(queryName);
//對query的key進行加密
sb.append(CommonUtils.getMD5(queryKey));
if (iterator.hasNext()) {
sb.append("&");
}
}
String newUrl = sb.toString();
RequestBody body = request.body();
String bodyToString = requestBodyToString(body);
TestBean testBean = GsonTools.changeGsonToBean(bodyToString, TestBean.class);
String userPassword = testBean.getUserPassword();
//加密body體中的使用者密碼
testBean.setUserPassword(CommonUtils.getMD5(userPassword));
String testGsonString = GsonTools.createGsonString(testBean);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), testGsonString);
Request.Builder builder = request.newBuilder()
.post(requestBody)
.url(newUrl);
return chain.proceed(builder.build());
}
}
複製程式碼
從上面可以看出我們先拿到body體的內容然後解析後,拿到對應的實體類,然後進行加密,再次建立一個新的body體裡面然後post過去,即可達到body體加密,我這只是一種body加密方法,也有可能是拿到body然後進行加密然後對加密後的東西加入head 當成簽名使用。
最終這種攔截器方式的加密也是一種統一程式碼入口的方式。
HEAD動態新增
在日常的開發中,可能每個介面對應的header不同有的多有的少。不可能說每個介面都寫一個攔截器進行新增頭部。這時候我們可以換個思維來考慮這個問題。怎麼做呢,其實也是為了統一程式碼,同一種操作不要再多個地方進行,這樣修改起來很麻煩。統一入口,統一出口。
public class TestInterceptor implements Interceptor {
private String newHost = "127.0.0.1";
private String path1 = "/test/upload/img";
private String path2 = "/test/upload/voice";
public static String requestBodyToString(RequestBody requestBody) throws IOException {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
return buffer.readUtf8();
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url();
//http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
String scheme = url.scheme();// http https
String host = url.host();// 127.0.0.1
String path = url.encodedPath();// /test/upload/img
String query = url.encodedQuery();// userName=xiaoming&userPassword=12345
StringBuffer sb = new StringBuffer();
sb.append(scheme).append(newHost).append(path).append("?");
Set<String> queryList = url.queryParameterNames();
Iterator<String> iterator = queryList.iterator();
for (int i = 0; i < queryList.size(); i++) {
String queryName = iterator.next();
sb.append(queryName).append("=");
String queryKey = url.queryParameter(queryName);
//對query的key進行加密
sb.append(CommonUtils.getMD5(queryKey));
if (iterator.hasNext()) {
sb.append("&");
}
}
String newUrl = sb.toString();
RequestBody body = request.body();
String bodyToString = requestBodyToString(body);
TestBean testBean = GsonTools.changeGsonToBean(bodyToString, TestBean.class);
String userPassword = testBean.getUserPassword();
//加密body體中的使用者密碼
testBean.setUserPassword(CommonUtils.getMD5(userPassword));
String testGsonString = GsonTools.createGsonString(testBean);
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), testGsonString);
Request.Builder builder = request.newBuilder()
.post(requestBody)
.url(newUrl);
switch (path) {
case path1:
builder.addHeader("token","token");
break;
case path2:
builder.addHeader("token","token");
builder.addHeader("uid","uid");
break;
}
return chain.proceed(builder.build());
}
}
複製程式碼
騷不騷,根據url中path的不同來動態的新增header,其實寫程式碼嗎?每個人實現的方式不同,只要路子對,怎麼擼都行,看個人。
請求日誌抓取
這個其實已經有現成的log攔截器了,大家日常開發中已經有用過,但是如果說我們只想看到我想要的,過濾那些不要的東西。怎麼辦呢。只能自己來自定義了。把自己需要的東西列印出來。以免太多每次看很亂。這時候怎麼通過攔截器完成這樣的一個騷操作呢。也很簡單,基於上面的基礎我們應該該拿到的都拿到了。
public class TestInterceptor implements Interceptor {
private String newHost = "127.0.0.1";
private String path1 = "/test/upload/img";
private String path2 = "/test/upload/voice";
private String TAG = "TestInterceptor";
public static String requestBodyToString(RequestBody requestBody) throws IOException {
Buffer buffer = new Buffer();
requestBody.writeTo(buffer);
return buffer.readUtf8();
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
HttpUrl url = request.url();
//http://127.0.0.1/test/upload/img?userName=xiaoming&userPassword=12345
String scheme = url.scheme();// http https
String host = url.host();// 127.0.0.1
String path = url.encodedPath();// /test/upload/img
String query = url.encodedQuery();// userName=xiaoming&userPassword=12345
RequestBody body = request.body();
String bodyToString = requestBodyToString(body);
Log.e(TAG,scheme);
Log.e(TAG,host);
Log.e(TAG,path);
Log.e(TAG,query);
if (response != null) {
ResponseBody responseBody = response.body();
long contentLength = responseBody.contentLength();
String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
Log.e(TAG,response.code() + ' '
+ response.message() + ' '
+ response.request().url()+' '
+ bodySize
);
Headers headers = response.headers();
for (int i = 0, count = headers.size(); i < count; i++) {
Log.e(TAG,headers.name(i) + ": " + headers.value(i));
}
}
return chain.proceed(request);
}
}
複製程式碼
根據自己的需求來吧,我只是簡單的列印一些東西。也是基於上面的程式碼來的。
ending
花了個把小時寫的東西,希望給老鐵們帶來的是知識的儲備而不是時間的浪費。不早了不早了下班了,