看過我以前博客的同窗會知道,19年我參與了一箇中臺項目,該項目是咱們公司和其餘幾大行業內知名公司一塊兒協力作的(感受個人描述有裝數字的嫌疑)。由於須要對接多方外部系統,這致使了咱們除了須要維護內部的開發環境、內部測試環境、正式生產環境以外,還須要維護一套公共的外部測試環境。前端
各個環境部署的狀況是:java
一、開發環境:部署在公司內部服務器上;web
二、內部測試環境:部署在阿里雲上;docker
三、外部測試環境:部署在騰訊雲上;數據庫
四、正式生產環境:部署在騰訊雲上;數組
這是背景交代。服務器
最近我在給咱們的web端增長權限控制(就是不給錢我就不給你看,給錢給的少了,我只給你看不給你改,給錢給夠了愛咋改咋改,就是這麼實在)。因爲咱們前端用的是咱們公司內部自主開發的前端解決方案,權限控制部分在底層代碼裏就已經實現了,我須要作的就是:把我要設置的權限腳本在須要插入的數據庫裏跑一遍,經過接口取出登錄用戶所擁有的權限數據,而後根據已有規則進行判斷便可。這個過程看起來和實現都很簡單,惟一稍微複雜一點的地方可能就是:權限的數據存在其餘系統的數據庫中,這也就意味着,咱們須要對接外部系統,經過和他們制定統一的規則,發送rest請求去獲取所需的數據。這個過程其實也很簡單,就是須要構造一個請求頭部,而後根據既定規則生成url便可。運維
不過這部分的後臺代碼以前小夥伴因爲寫別的模塊需求已經實現了,能夠躺在樹下吃棗這件事我是最開心的啦(可我纔不會嗦出來~~)。前端代碼一鼓作氣,寫的感受手超級順,當時老開心了,追着測試後面催人家趕忙測(以前每天被他們催着改bug,可不得在他們忙的時候給添點亂咋的)。等測試回過神有時間開始測個人單子的時候,他告訴我-內部測試環境和外部測試環境都gg了,顯示爲無權限,不管當前的用戶是否有設置權限,甚至是超級管理員(超級管理員默認擁有全部的權限)。maven
這樣我就不服氣了,不過環境既然掛了,並且看着也確實是個人緣由,那不服也得找到緣由並修復掉(畢竟是一個有原則的職場人)。post
找了一圈,發現是對外部系統的配置,沒有加到內部測試環境和外部測試環境,而我構造的url及請求頭部驗證 的內容都與配置息息相關,因此在測試環境,實際向外部的請求根本未成功發出過(說到這個,我其實不是很理解,爲啥測試環境須要運維手動添加配置信息,而咱們本地都是直接某我的寫在yml配置文件中便可)。emmm,果斷讓運維大佬幫忙加了一下,心想這下總在沒有問題了吧。
而後費勁八擦終於配置都加好了,環境也更新好了以後,發現外部測試環境正常了,而後內部測試環境依舊gg。這就讓人很費解了,講道理代碼是同一套,沒道理一個能夠一個不能夠呀。找他們的區別,想了半天也只有多是內部測試環境的配置沒有加上,而後我在代碼裏打了一堆的日誌,發現都是能正常取出配置信息的,可是內部測試環境依舊掛着的,而後我擔憂我理解的有誤,依舊懷疑是運維沒有配好,拉着運維讓他給我看了docker鏡像內容,好吧,確實是有配置的。那問題就不知道在哪裏了呀?!!!不得已找了大神,大神告訴我,我加的權限在他本地也是一直在報錯(報錯500,和內部測試環境日誌中打印出來的一致)....嗯????難道只有個人本地開發環境是正常的?趕忙找了周圍的幾個小夥伴試試,本地都是正常的,這我就放心了~~那麼,問題來了,爲啥大神的本地在報錯?這個時候,正常的思路確定是找不一樣呀~~
我和大神最大的不一樣就是,我是在公司總部上班,而他是在公司在外地的辦事處上班(可是咱們是一個項目組的,結構就是如此神奇)。這個時候,大神一拍腦門:不會是內部測試環境給大家總部的網關和騰訊雲配了白名單吧(總部是能理解的啦,至於騰訊雲,大概是由於騰訊是金主爸爸?)。找運維確認了下,還真的是!那麼這裏有有一個問題呀,就算沒有開白名單,對外部系統的訪問也是構造了請求頭和url,走正常的rest請求的流程也應該是能正常帶回來數據的,而不該該是報錯500(HTTP500是服務器錯誤,具體緣由請自行百度)。大神說:來,我們一步一步來,先用postman模擬下實際向外發送的請求,看看是否正常。而後大神發現,用根據個人規則生成的請求頭部和url,一直會報500,大神表示受不了了,他要找對接系統的開發人員看看了。對方人員看了一眼:你這個authorization咋看着怪怪的?他甩了一個根據他們的規則生成的authorization出來,看着也確實是比較符合一般的驗證字段結構。對照了下代碼,發現兩邊的代碼結構基本是同樣的,代碼貼出以下:
//咱們系統頭部驗證的構造
private HttpHeaders defaultHttpHeaders() { ... String authorization = "Basic " + Base64Utils.encode((username + ":" + password).getBytes()); ....
}
//對方系統頭部驗證的構造 private HttpHeaders defaultHttpHeaders() { ... String authorization = "Basic " + new String(Base64.encodeBase64((username + ":" + password).getBytes())); .... }
咱們構造的頭部驗證惟一的區別就在於,咱們用了Base64Utils默認的 toString()方法,而對方則是new了一個新的String對象。
在個人方法中,是將Base64編碼後的結果以字節數組的的方式和前面的字符串常量進行拼接,這個過程當中,字節數組將會被 java 自帶的 toString()方法轉化爲 string 類型,toString() 方法源碼以下:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
所以,我構造出的 authorization 長這樣:
而對方使用的是 new String() 方法,即將字節數組直接轉化爲一個新的字符串,轉換的源碼以下:
public String(byte bytes[]) { this(bytes, 0, bytes.length); }
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
}
對方構造的 authorization 長這樣:
從以上源碼能夠看出,對方是生成一個新的 string 變量,再將根據既定規則構造的內容進行 base64 編碼解碼加密的過程,而咱們用到的 toString() 方法,能夠理解爲返回一個"由類名(對象是該類的一個實例)、at 標記符「@」和此對象哈希碼的無符號十六進制表示組成"的字符串。就算不理解前面的balabala描述,也已經知道,咱們的 authorization 的構成不知足意義上 認證的需求。
問題找到了,那就趕忙修復卡~~(看着晚上能夠早點回家坐在餐桌旁邊次飯飯,開森)
然而,有句老話叫「樂極生悲」,老人說的話每每有他的道理....
在我修復認證的構造過程當中,項目組的小哥哥發了個版本(就是好比咱們本來開發環境是 0.0.1-SNAPSHOT 快照版本,在發了版本以後,生產環境爲 0.0.1 版本,而咱們開發環境版本 +1 變成 0.0.2-SNAPSHOT 版本)。然而,我並無關注到這件事,依舊在提交代碼以後開開心心的在 jenkins上啓動 job 編譯更新咱們的內部測試環境驗證。滿懷激動的等着 job 的進度條到達100%,打開測試環境狂刷。然而。。。內部測試環境宛如米有提交任何代碼。我都懷疑是否是由於我打開測試環境太快了,實際測試環境並無徹底更新部署完成。默默等待了 10 min(別問我爲啥是10分鐘,經驗告訴個人時長),滿懷忐忑的驗證,果真依舊掛着。又到了百思不得其解的時候,正確的解決方式是啥?固然是抱大神大腿啊。大神在本地驗證,一塊兒正常,而後咱們倆在電話裏相互看着電腦屏幕無言,沉默良久,大神忽然一拍腦門(他的老習慣)說:會不會是 部署的版本號沒有調整啊?想一想都以爲有可能。這就又到了運維大佬出場的時候了,磨着運維小哥哥進入docker 倉庫,查看個人操做記錄是否是成功了,以及操做的實際版本號。果真~~眼淚流下來(實際部署的版本號是咱們開發看不到的,只有運維能夠控制)。
眼睜睜看着運維小哥哥修改好了版本號以後,再磨着他編譯部署了一遍內部測試環境(畢竟咱們是看不到實際是否是部署成功了啊,我就是磨人的小妖精)。懷着宛如第一次見本身親兒子的老父親那種心情,顫抖着小手手打開內部測試環境,哇,好了啊,哇,能夠回家吃飯飯了啊,哇,好開心啊(其實此刻在寫文的我一點都不開心,由於我心心念唸的寒天又被放進了別人的杯子,以前在廈門喝到寒天愛玉超級愛的,回上海以後發現也有,滿懷期待的點了兩次。。。兩次啊,每一次都被放進了別人的杯子!!!)
此部分我後面還會增長 「maven版本管理」相關的內容,先立好flag。