麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 開(kāi)發(fā) > Java > 正文

如何動(dòng)態(tài)改變Retrofit的base url和rest版本詳解

2024-07-14 08:42:18
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

概述

隨著Google對(duì)HttpClient 摒棄,和Volley的逐漸沒(méi)落,OkHttp開(kāi)始異軍突起,而Retrofit則對(duì)okHttp進(jìn)行了強(qiáng)制依賴。

Retrofit是由Square公司出品的針對(duì)于Android和Java的類(lèi)型安全的Http客戶端,

如果看源碼會(huì)發(fā)現(xiàn)其實(shí)質(zhì)上就是對(duì)okHttp的封裝,使用面向接口的方式進(jìn)行網(wǎng)絡(luò)請(qǐng)求,利用動(dòng)態(tài)生成的代理類(lèi)封裝了網(wǎng)絡(luò)接口請(qǐng)求的底層,

其將請(qǐng)求返回javaBean,對(duì)網(wǎng)絡(luò)認(rèn)證 REST API進(jìn)行了很好對(duì)支持此,使用Retrofit將會(huì)極大的提高我們應(yīng)用的網(wǎng)絡(luò)體驗(yàn)。

REST

既然是RESTful架構(gòu),那么我們就來(lái)看一下什么是REST吧。 

REST(REpresentational State Transfer)是一組架構(gòu)約束條件和原則。 

RESTful架構(gòu)都滿足以下規(guī)則: 

(1)每一個(gè)URI代表一種資源; 

(2)客戶端和服務(wù)器之間,傳遞這種資源的某種表現(xiàn)層; 

(3)客戶端通過(guò)四個(gè)HTTP動(dòng)詞,對(duì)服務(wù)器端資源進(jìn)行操作,實(shí)現(xiàn)”表現(xiàn)層狀態(tài)轉(zhuǎn)化”。

下面話不多說(shuō)了,來(lái)開(kāi)始本文的正文吧

1. 需求與前提

base url

默認(rèn)base url: https://cloud.devwiki.net

測(cè)試版 url : https://dev.devwiki.net

私有云版本url: https://private.devwiki.net

rest 版本

  • /rest/v1/
  • /rest/v2/
  • /rest/v3/

需求點(diǎn)

  • 大部分接口使用 cloud host, 部分接口使用 private host
  • 大部分接口使用 rest/v3 版本, 部分接口使用 v2, v1版本.
  • 每個(gè)host 都有可能存在 rest v1, v2, v3的接口

2. 實(shí)現(xiàn)思路

okhttp 可以添加攔截器, 可在發(fā)起訪問(wèn)前進(jìn)行攔截, 通常我們會(huì)在 攔截器中統(tǒng)一添加 header, 比如:

class HeaderInterceptor implements Interceptor {  private static final String ENCODING_GZIP = "gzip"; private static final String CONTENT_TYPE_JSON = "application/json;charset=UTF-8"; private static final String HEADER_CONTENT_TYPE = "Content-Type"; private static final String HEADER_ACCEPT_TYPE = "application/json"; private static final String HEADER_CONTENT_ENCODING = "Content-Encoding"; private final static String CHARSET = "UTF-8";  @Override public Response intercept(Chain chain) throws IOException {  Request originRequest = chain.request();  Request.Builder newBuilder = originRequest.newBuilder();  newBuilder.addHeader("Accept", HEADER_ACCEPT_TYPE);  newBuilder.addHeader("Accept-Charset", CHARSET);  newBuilder.addHeader("Accept-Encoding", ENCODING_GZIP);  newBuilder.addHeader("Accept-Language", Locale.getDefault().toString().replace("_", "-"));  newBuilder.addHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON);  return chain.proceed(newBuilder.build()); }}

同理我們也可以在所有請(qǐng)求中添加統(tǒng)一的uuid 或者 key 進(jìn)行防劫持或者認(rèn)證. 比如:

Request originRequest = chain.request();if (paramsMap != null) { HttpUrl originUrl = originRequest.url(); HttpUrl.Builder newBuilder = originUrl.newBuilder(); for (String key : paramsMap.keySet()) {  newBuilder.addEncodedQueryParameter(key, paramsMap.get(key)); } HttpUrl newUrl = newBuilder.build(); Request newRequest = originRequest.newBuilder().url(newUrl).build(); return chain.proceed(newRequest);}return chain.proceed(originRequest);

那么, 同樣我們可以再攔截器中進(jìn)行host 和 path的替換, 那么怎么替換呢?

3. 實(shí)現(xiàn)過(guò)程

3.1 定義host 類(lèi)型和 rest 版本

host類(lèi)型:

interface HostName { String CLOUD = "CLOUD"; String PRIVATE = "PRIVATE"; String DEV = "DEV";} interface HostValue { String CLOUD = "https://www.baidu.com"; String PRIVATE = "https://private.bidu.com"; String DEV = "https://dev.baidu.com";}

rest 版本:

interface RestVersionCode { String EMPTY = "EMPTY"; String V1 = "V1"; String V2 = "V2"; String PRIVATE = "PRIVATE";} /** * path 前綴值 */interface RestVersionValue { String EMPTY = ""; String V1 = "rest/v1"; String V2 = "rest/v2"; String PRIVATE = "rest/private";}

設(shè)置一個(gè)默認(rèn)的 host 和 rest 版本, 然后在需要更改host和rest 版本的請(qǐng)求接口處添header, 根據(jù)header設(shè)置來(lái)變更.

interface BaiduApiService {  @GET("s") Observable<Response<Object>> search(@Query("wd")String wd);  @GET("s") @Headers({UrlConstants.Header.REST_VERSION_V1}) Observable<Response<Object>> searchChangePath(@Query("wd")String wd);  @GET("s") @Headers({UrlConstants.Header.HOST_DEV}) Observable<Response<Object>> searchChangeHost(@Query("wd")String wd);  @Headers({UrlConstants.Header.HOST_PRIVATE, UrlConstants.Header.REST_VERSION_PRIVATE}) @GET("s") Observable<Response<Object>> searchChangeHostPath(@Query("wd")String wd);}

header 的可選值:

interface Header { String SPLIT_COLON = ":"; String HOST = "HostName"; String HOST_CLOUD = HOST + SPLIT_COLON + HostName.CLOUD; String HOST_PRIVATE = HOST + SPLIT_COLON + HostName.PRIVATE; String HOST_DEV = HOST + SPLIT_COLON + HostName.DEV; String REST_VERSION = "RestVersion"; String REST_VERSION_V1 = REST_VERSION + SPLIT_COLON + RestVersionCode.V1; String REST_VERSION_V2 = REST_VERSION + SPLIT_COLON + RestVersionCode.V2; String REST_VERSION_PRIVATE = REST_VERSION + SPLIT_COLON + RestVersionCode.PRIVATE; String REST_VERSION_EMPTY = REST_VERSION + SPLIT_COLON + RestVersionCode.EMPTY;}

然后是解析:

class RequestInterceptor implements Interceptor {  @Override public Response intercept(Chain chain) throws IOException {  Request originRequest = chain.request();  HttpUrl originUrl = originRequest.url();  HttpUrl.Builder newBuilder;   String hostType = originRequest.header(UrlConstants.Header.HOST);  System.out.println("hostType:" + hostType);  if (hostType != null && hostType.length() > 0) {   String hostValue = UrlManager.getInstance().getHost(hostType);   HttpUrl temp = HttpUrl.parse(hostValue);   if (temp == null) {    throw new IllegalArgumentException(hostType + "對(duì)應(yīng)的host地址不合法:" + hostValue);   }   newBuilder = temp.newBuilder();  } else {   newBuilder = new HttpUrl.Builder()     .scheme(originUrl.scheme())     .host(originUrl.host())     .port(originUrl.port());  }  String restVersion = originRequest.header(UrlConstants.Header.REST_VERSION);  System.out.println("restVersion:" + restVersion);  if (restVersion == null) {   restVersion = UrlConstants.RestVersionCode.V2;  }  String restValue = UrlManager.getInstance().getRest(restVersion);  if (restValue.contains("/")) {   String[] paths = restValue.split("/");   for (String path : paths) {    newBuilder.addEncodedPathSegment(path);   }  } else {   newBuilder.addEncodedPathSegment(restValue);  }  for (int i = 0; i < originUrl.pathSegments().size(); i++) {   newBuilder.addEncodedPathSegment(originUrl.encodedPathSegments().get(i));  }   newBuilder.encodedPassword(originUrl.encodedPassword())    .encodedUsername(originUrl.encodedUsername())    .encodedQuery(originUrl.encodedQuery())    .encodedFragment(originUrl.encodedFragment());   HttpUrl newUrl = newBuilder.build();  System.out.println("newUrl:" + newUrl.toString());  Request newRequest = originRequest.newBuilder().url(newUrl).build();  return chain.proceed(newRequest); }}

為了能動(dòng)態(tài)設(shè)置host, 我們需要一個(gè)map來(lái)存儲(chǔ)host 類(lèi)型和值.

private Map<String, String> hostMap;private Map<String, String> restMap; private UrlManager() { hostMap = new HashMap<>(16); for (UrlConstants.Host host : UrlConstants.Host.values()) {  hostMap.put(host.getName(), host.getValue()); } restMap = new HashMap<>(); for (UrlConstants.Rest rest : UrlConstants.Rest.values()) {  restMap.put(rest.getVersion(), rest.getValue()); }} //更新host 的值public void setHost(String name, String value) { if (hostMap.containsKey(name)) {  HttpUrl httpUrl = HttpUrl.parse(value);  if (httpUrl == null) {   throw new IllegalArgumentException("要存入的Host " + name + "對(duì)應(yīng)的value:"     + value + "不合法!");  }  hostMap.put(name, value); } else {  throw new NoSuchElementException("沒(méi)有找到已經(jīng)定義的Host名稱(chēng):" + name + ",請(qǐng)先在" +    "net.devwiki.manager.UrlConstants.Host中定義!"); }} //根據(jù)host 獲取值public String getHost(String name) { if (!hostMap.containsKey(name)) {  throw new NoSuchElementException("沒(méi)有找到已經(jīng)定義的Host名稱(chēng):" + name + ",請(qǐng)先在" +    "net.devwiki.manager.UrlConstants.Host中定義!"); } return hostMap.get(name);}

這樣就可以動(dòng)態(tài)替換host 和 rest版本了.

4.測(cè)試運(yùn)行

測(cè)試代碼:

private static void testRequest() { BaiduRest rest = new BaiduRest();  testDefault(rest);  testChangeHost(rest);  testChangePath(rest);  testChangeHostPath(rest);}

測(cè)試運(yùn)行結(jié)果:

ostType:null
restVersion:null
newUrl:https://www.baidu.com/rest/v2/s?wd=123
九月 07, 2018 11:36:58 上午 okhttp3.internal.platform.Platform log
信息: --> GET https://www.baidu.com/rest/v2/s?wd=123 http/1.1
九月 07, 2018 11:36:58 上午 okhttp3.internal.platform.Platform log
信息: <-- 302 Found https://www.baidu.com/rest/v2/s?wd=123 (83ms, 154-byte body)
九月 07, 2018 11:36:58 上午 okhttp3.internal.platform.Platform log
信息: --> GET http://www.baidu.com/s?wd=123&tn=SE_PSStatistics_p1d9m0nf http/1.1
九月 07, 2018 11:36:58 上午 okhttp3.internal.platform.Platform log
信息: <-- 200 OK http://www.baidu.com/s?wd=123&tn=SE_PSStatistics_p1d9m0nf (46ms, unknown-length body)
hostType:DEV
restVersion:null
newUrl:https://dev.baidu.com/rest/v2/s?wd=123
九月 07, 2018 11:36:58 上午 okhttp3.internal.platform.Platform log
信息: --> GET https://dev.baidu.com/rest/v2/s?wd=123 http/1.1
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: <-- 302 Found https://dev.baidu.com/rest/v2/s?wd=123 (154ms, 154-byte body)
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: --> GET http://developer.baidu.com/error.html http/1.1
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: <-- 301 Moved Permanently http://developer.baidu.com/error.html (18ms, 73-byte body)
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: --> GET https://developer.baidu.com/error.html http/1.1
hostType:null
restVersion:V1
newUrl:https://www.baidu.com/rest/v1/s?wd=123
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: <-- 200 OK https://developer.baidu.com/error.html (157ms, unknown-length body)
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: --> GET https://www.baidu.com/rest/v1/s?wd=123 http/1.1
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: <-- 302 Found https://www.baidu.com/rest/v1/s?wd=123 (46ms, 154-byte body)
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: --> GET http://www.baidu.com/s?wd=123&tn=SE_PSStatistics_p1d9m0nf http/1.1
九月 07, 2018 11:36:59 上午 okhttp3.internal.platform.Platform log
信息: <-- 200 OK http://www.baidu.com/s?wd=123&tn=SE_PSStatistics_p1d9m0nf (54ms, unknown-length body)
hostType:PRIVATE
restVersion:PRIVATE
newUrl:https://private.bidu.com/rest/private/s?wd=123

結(jié)果按照設(shè)置進(jìn)行了host 和 rest 的變更.

5. 項(xiàng)目代碼

項(xiàng)目代碼地址: Dev-Wiki/OkHttpDemo

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)VeVb武林網(wǎng)的支持。


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JAVA教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 亚洲第九十九页 | 99激情| 国产精品1区2区在线观看 | 欧美成人午夜一区二区三区 | 午夜视频在线看 | 欧美成人se01短视频在线看 | 精品国产一区二区三区四区阿崩 | 久久久噜噜噜久久熟有声小说 | 中文字幕综合在线观看 | 国产女厕一区二区三区在线视 | av观看国产| 茄子福利视频 | 一本色道久久99精品综合蜜臀 | 国产99精品 | 毛片a区| 欧美成人免费电影 | 中国字幕av | 欧洲伊人网 | 欧美日韩在线播放 | 免费一级特黄毛片视频 | 一区二区三区日韩 | 国产69精品福利视频 | 免费亚洲视频在线观看 | 久久国产精品电影 | 激情亚洲一区二区 | 日日草夜夜操 | 综合网天天色 | 91成人久久| 久久久青| 国产91在线亚洲 | 视频一区二区国产 | 91久久国产综合精品女同国语 | 欧美视频一二三区 | 亚洲一区二区三区精品在线观看 | 日韩欧美高清片 | 免费毛片在线视频 | 在线成人精品视频 | 久久久久免费精品国产小说色大师 | 露脸各种姿势啪啪的清纯美女 | 久久久www成人免费毛片 | 欧美中文字幕一区二区三区亚洲 |