小明一個剛入行安卓的小萌新,剛剛在測試小姐姐那裏交過學費(捱過罵)瞭解到軟件開發過程當中是須要區分正式、測試環境的。可是他稍加思考就能想到測試、正式環境的區別僅僅是host不同而已,其餘的好比接口名、參數名、返回的json格式均如出一轍。因而他立刻找到了解決方案,平時都用測試環境的,到上線的時候再換回正式環境不就能夠了?在一次開發中須要請求三個不一樣接口,說幹就幹,因而小明就寫出瞭如下代碼,準備在上線時全局搜索www.test.com改爲www.release.com,提交之後開開心心下班撩妹去了。面試
//請求接口1
NetWorkUtil.request("http://www.test.com?action=a1")
//請求接口2
NetWorkUtil.request("http://www.test.com?action=a2")
//請求接口3
NetWorkUtil.request("http://www.test.com?action=a3")複製代碼
三天之後,產品經理跑過來講要加一個需求,新增了好幾個接口,小明表示本身表現的機會到了,一古腦兒所有包下來了。但是作着作着發現有點不對勁啊,每次請求接口的時候都須要複製http://www.test.com這個域名,但是產品錦鯉追的緊啊,沒辦法先就這麼辦吧,實現了需求上線之後再說。數據庫
一週過去了,上線時間到了。測試小姐姐又跑過來問小明這個正式包的數據怎麼不對,仍是測試環境的?小明趕忙道歉,想起來了上線前須要修改域名這個事情,本身竟然忘記了。內心一萬隻草泥馬飛過,小明趕忙的匆匆忙忙地改完項目裏全部接口請求的地方,這才鬆一口氣,給測試小姐姐買了個奶茶打了個新包,這個版本終於成功上線了,還真是不容易啊。json
一天之後,小明被項目經理叫到了辦公室,把小明狠狠批了一頓。原來是小明有個地方忘記改了,線上用戶的操做被記錄到了測試數據庫了。項目經理爲了解決這個問題,將最近一天測試環境的該數據所有導入到了正式環境才解決,固然還收到了很多的投訴。不過還好這個數據不是核心數據,不是那麼重要,否則小明的機票估摸着差很少就到手了。windows
小明痛定思痛,堅定要杜絕這種低級錯誤。因而他把須要改域名這個事情已經記錄到備忘錄裏天天提醒了,除此以外,聰明的他還想到了一個辦法,就是用一個全局的變量對域名進行保存,在上線前只須要切換一次就好了,相似於這種:後端
companion object {
const val HOST = "http://www.test.com"
}
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
setContentView(R.layout.activity_main)
//請求接口1
NetWorkUtil.request("$HOST?action=a1")
//請求接口2
NetWorkUtil.request("$HOST?action=a2")
//請求接口3 NetWorkUtil.request("$HOST?action=a3")
}複製代碼
小明終於沒有犯線上的低級錯誤了,可是後面業務需求愈來愈繁雜,服務端使用的域名也愈來愈多,而且不少第三方的api好比推送、bugly監測等也都須要切換id。每次上線須要修改一堆的域名和id。小明天天心態都跟高考同樣,緊張又懼怕,生怕本身再出問題,被強制送機票。並且就算在測試階段,測試小姐姐偶爾也會讓他打一個release包測試,雖然內心千萬只草泥馬不肯意,可是也沒辦法,先改爲線上的域名吧,打完之後再改回來唄!因而小小明逐漸地熟悉了這一套切換方式,直到他看到了那一篇技術博客,小明他。。。哭了。api
小明看到的文章正是一篇關於測試和正式環境切換的技術文章,該文通俗易懂,還提供了完整的方案,小明看完以爲這不就是爲本身準備的麼,因而按照文章裏的方式嘗試了起來。文章中說到能夠根據當前app是debug仍是release來切換host,大概實現以下,首先在Application的onCreate()中獲取到當前是不是debug模式,而且用靜態變量進行記錄,接下來須要區分測試、正式環境的時候就根據這個flag來判斷便可。瀏覽器
class MyApplication: Application() {
companion object {
var IS_DEBUG = true
}
override fun onCreate() {
super.onCreate()
IS_DEBUG = (applicationInfo.flags != 0 && ApplicationInfo.FLAG_DEBUGGABLE != 0)
}
}複製代碼
小明收到了該文章的啓發,因而在項目全部須要區分測試、正式環境的地方都對上面的flag進行了判斷,其代碼大體以下:bash
companion object {
val HOST1 = if(MyApplication.IS_DEBUG)"http://www.test1.com" else "http://www.release1.com"
val HOST2 = if(MyApplication.IS_DEBUG)"http://www.test2.com" else "http://www.release2.com"
val HOST3 = if(MyApplication.IS_DEBUG)"http://www.test3.com" else "http://www.release3.com"
}複製代碼
到了這裏終於小明終於能夠鬆口氣不用設置備忘錄,每次上線不用爲了改域名問題而提心吊膽了,域名會智能地根據當前是debug包仍是release包還自動賦值。可是後面加在這裏的域名和第三方api愈來愈多,因而小明還在此基礎上觸類旁通,進行了一波優化。小明瞭解到在系統打包的時候,若是在build.gradle文件中的buildTypes裏添加debug和release的相應配置,系統在build/generated/source/buildConfig目錄下會自動生成BuildConfig類,系統自動生成的類大概以下:服務器
/**
* Automatically generated file. DO NOT MODIFY
*/
package xx.xx.xx;
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String APPLICATION_ID = "xx.xx.xx";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
}
複製代碼
這裏面的字段是能夠添加的,好比在build.gradle中設置好須要區分測試、正式環境的host,能夠先按以下規則定義好網絡
buildTypes {
debug {
buildConfigField "String", "URL", "\"www.test.com\""
}
release {
buildConfigField "String", "URL", "\"www.release.com\""
}
}
複製代碼
則在編譯的時候,系統會自動在BuildConfig中加入如下代碼
public static final boolean DEBUG = true;
public static final String URL= "www.test.com";//若是是release包中會自動生成www.release.com
咱們能夠看到,在實際開發的時候根本不須要去設置當前是哪一個域名,而是系統會自動來判斷,從而在實際的業務需求開發時咱們只須要使用BuildConfig.URL便可,小明將全部的域名以及第三方sdk須要的appkey都放到了buildTypes裏,因而小明的代碼能夠改爲這樣子了:
//請求接口1
NetWorkUtil.request("${BuildConfig.URL}?action=a1")
//請求接口2
NetWorkUtil.request("${BuildConfig.URL}?action=a2")
//請求接口3
NetWorkUtil.request("${BuildConfig.URL}?action=a3")複製代碼
固然這裏URL最好封裝到Common層中,這裏就很少說,不是本文的重點。通過這一波的修改終於不用在每次上線時都修改URL了,而是系統會自動選擇好URL,咱們直接使用就能夠了。
按照上面的方式,一些小型的項目基本就沒問題了。可是用在大型項目裏問題就比較明顯了,我這裏隨便列舉幾個吧。
1.大項目的測試環境有可能不止一個,那麼具體用哪一個還得作一個手動切換入口
2.大廠的測試人員常常測試出指定response數據下的bug,開發人員拿到bug之後要連測試的代理,恢復現場才能復現,影響測試人員測試其餘的bug,並且不方便查看抓包信息
3.在平常的開發測試時安裝的是debug包,因此在上線之後,想看一下線上的效果又須要卸載從新安裝release包,等下個版本開發時又卸載線上的安裝debg版,這一波操做很是的麻煩
那麼,有沒有辦法能夠解決以上的問題呢,答案固然是有的,這就是筆者今天要給你們重點介紹的host映射法。
在此以前,首先給你們簡單介紹一下IP地址。你們確定都知道,每臺在因特網的電腦都會有一個惟一的IP地址,IP地址至關因而你電腦的名字,其餘電腦就經過IP地址來訪問你的地址,就至關於你們經過喊你的名字來將你和其餘人進行區分同樣。
接下來再給你們介紹一下域名,域名就至關於別人給你起的外號,別人嫌棄你的本名叫起來不順口,就喜歡叫你外號。作過服務端開發的同窗確定知道,就算沒有域名,只憑ip地址同樣能夠訪問到服務器。可是若是讓大家訪問淘寶京東的時候,每次輸入xx.xx.xx.xx這種ip地址你們確定不會喜歡的,也沒人能記得住,可是taobao.com就不同了,朗朗上口,過目不忘。
最後再給你們介紹一下DNS解析,這個名詞聽上去很高大上,可是其實理解起來特別簡單。DNS解析就是將域名和IP給匹配上的過程,否則誰知道你的外號是給誰起的,確定會有公證人來統計這一一對應的信息。在咱們訪問網址的時候,表現上是訪問的域名,但其實中間會通過一層dns解析,最終變成了訪問ip地址。
如上圖,例如小明想要訪問種子網站1,因而小明在瀏覽器裏輸入了www.zzwz1.com,接下來瀏覽器會拿着小明輸入的域名訪問DNS解析中心,詢問小明的網站ip是多少,詢問到了之後才能真正地訪問種子網站1,而不是錯誤地訪問到種子網站2。
知道了上面那些概念之後,有一個想法油然而生,那我是否是能夠經過修改解析方式來區分測試環境和正式環境呢?若是能夠的話,咱們項目裏就讓它一直是www.release.com好了,在我須要測試的時候,我把這個域名解析到測試機器上,這樣不就訪問到了測試環境了麼?
事實證實這樣作是能夠的,並且是合法正規渠道就能夠作到了。以windows爲例,在c:\\windows\System32\drivers\etc下面有一個hosts文件,該文件就是Windows官方提供用來修改DNS解析用的,凡是在該文件裏定義的解析方式將再也不走入正規的解析流程。
咱們打開該文件,Window也有一些對該文件的介紹,大概就是說咱們能夠經過寫入IP地址而後空格域名的方式指定該域名解析的IP地址,從而覆蓋其真正的主機。有過一些後端基礎的同窗可能知道,爲了方便咱們常常將127.0.0.1爲了方便從而替換成localhost,爲的就是在訪問本機網址的時候能夠經過localhost的方式,寫起來更簡單一些。
因此咱們須要作的就是在測試的時候修改這個hosts文件,好比測試環境下服務端的ip地址爲yy.yy.yy.yy咱們只須要在hosts文件里加上如下一句話便可
yy.yy.yy.yy release.com
這樣一旦咱們app訪問release.com的時候,本機就會將該域名指向IP爲yy.yy.yy.yy的電腦。
服務端首先須要將測試環境和正式環境分別部署在不一樣的電腦上,其次正式環境和測試環境的域名都保證是同一個,這兩條在稍微正規一些的項目應該都是沒問題的。接下來服務端只須要告知客戶端全部測試服務端的ip地址,客戶端同窗將全部的ip都保存到hosts裏面,在使用的時候相應地放開某些限制就能夠了,作法以下圖:
在須要使用測試環境1時就放開相應地限制,讓該域名走向本身想要地服務端。若是想要切換回線上,也不須要修改任何客戶端代碼,甚至不須要從新打包,而是修改一下hosts將全部測試環境地限制所有取消便可,是否是很是地方便呢!
在複雜項目中,常常會出現多個域名的狀況,這樣每次切換環境須要改的host條數太多,還真是有點麻煩,這裏能夠經過一些專業切換host的工具來解決,好比switchhosts工具就很是好用,能夠自定好平時工做中經常使用的幾套host組合,保存到switchhosts中,能夠實現一鍵切換
以上切換host是在電腦上實現的,因此還須要測試機和電腦連同一個網,而且使用charles、fiddler等代理工具對手機網絡進行代理。若是本身只須要修改而不須要抓包的話,一樣能夠下載手機上的代理app,相似app有不少,好比知名的HostGo就很好用。
1.對服務端要求更高
2.開發時不當心hosts忘記切換的話會把數據傳入到正式環境中,或者反之
3.和服務端溝通成本較高
操做複雜性:第一種方式因爲須要複製粘貼進行替換,因此仍是有一些工做量的,第二種要看當前項目是否有多個測試環境,若是有的話則也須要測試人員去手動切換,若是沒有的話就不須要任何操做,第三種方式因爲切換的時候須要修改host,也是須要操做的。
容錯性:第一種方式有可能會替換錯誤,因此容錯性差,其餘兩種基本都不會有問題
規範性:規範性是從代碼質量的方面來看,第一種方式是一直修改老代碼,明顯是低分,第二種方式存在須要切換不一樣測試環境的可能性,須要在debug模式下加一些只用來測試的和功能無關的代碼。
溝通成本:第二種方式在和測試聯調的時候,可能會更費勁一些,好比具體是哪一個接口,還要把response數據發來本地maplocal才能復現問題。而切換host的方式,也須要和測試人員溝通當前復現的測試環境是哪一個,而且須要和服務端溝通獲取到測試環境的IP地址。若是測試人員測試出了接口bug,只須要把其host文件發來替換本地的host文件就能夠復現問題了。
拓展性:拓展性是從功能的強大程度來對比,全局替換的方式,每新增一個host就須要多替換一個,到後面就愈來愈重,第二種的話因爲在新增測試環境方面表現欠佳,每次新增一個測試環境就須要修改客戶端代碼來提供切換入口,因此也不能給高分。
是否須要從新安裝:在測試的時候的apk包放到線上時,因爲接口須要替換,因此確定須要從新打包,可是使用切換host的方式,若是測試的時候就是用的release包,那麼能夠直接上線,就算是debug包,也同樣把hosts文件裏的dns限制註釋掉就能夠訪問線上數據的。
本文筆者以工做中必用的測試、正式環境切換爲題,介紹了不一樣經歷的同窗分別是怎麼實現的,最後重點介紹了筆者推薦的切換Host的方式。你們項目裏用第二種仍是第三種根據項目狀況而定,若是是小項目的話用第二種就足以,可是第三種你們也仍是要能看懂,除此以外,DNS也是大廠在面試的時候喜歡問的一個點。最後多謝同窗們耐心地看完了文章,對裏面內容有疑義或者有不懂的地方歡迎一塊兒探討,共同進步!