localhost工具:原生程式碼的遠端之路

京東雲開發者發表於2023-12-07

在日常的開發過程中,原生程式碼遠端除錯一直是最理想的開發狀態。本文透過介紹京東集團內開發的一個輕量簡單的小工具”localhost”,從多角度的方案思考,到原理介紹,到最終的方案落地,在開發階段發現問題,解決問題。

背景

起源

在很早之前,我參加了一個技術分享大會,當時現場是分享了一個本地在遠端叢集中的雲原生開發方案,當時聽完了之後就對其中本地開發的同時可以遠端執行服務這部分非常感興趣,本身作為前端開發來說,確實每次驗證一些問題的時候,在本地開發階段無法在真實的環境中除錯,需要本地測試,打包,發版,驗證,在處理一些相容問題的時候,這個過程可能要重複很多次,會浪費很多時間。同時作為賽博雲測的開發來說,在雲測平臺上經常會遇到一些前端開發同學需要除錯不同裝置的相容問題,有的甚至頂不住需要線下借裝置。雲測平臺存在的意義的就是能夠線上化解決一切移動端的問題,開發的問題也是問題。

痛點

試想這樣一個場景,測試同學上報了一個手機頁面開啟白屏的問題,雲測平臺上這個手機確實復現了這個問題,你搜尋了一些可能的處理方式,然後修改發版驗證,發現並沒有用,這個時候該怎麼辦。

或者後端同學提前開發完,發了測試環境給前端同學實時除錯介面,需要不停的修改欄位或者邏輯或者debug除錯問題,這個時候該怎麼辦。

又或者低程式碼的開發同學,寫完物料元件之後想在實際裝置中看看效果,但是不得不單獨找裝置來看,或者等測試同學報bug,時間都浪費在這個過程中,該怎麼辦。

我想開發同學或多或少都經歷過這些場景,在聯調或者除錯一些問題的時候,總是沒辦法做到本地改完程式碼儲存立馬就能檢視。作為一個工具平臺,怎麼去解決這個痛點並且能夠更好的和平臺結合,這個想法就一直在我心裡存在著。

思考

從聽那場分享會的時候,我就已經在想有什麼方案可以實現這個目的,當時分享中說到了雲原生開發的原生程式碼的處理部分,讓我沒想到的是,他們的方案非常直接,直接到將原生程式碼“搬”到了遠端,實時在本地儲存的時候將程式碼同步到遠端的開發容器中,並且為了解決 http 協議傳輸的時間消耗,自定義了一套協議進行程式碼的同步,當然這個方案對於我所設想的場景實在是大材小用了,不過真的非常膽大心細,也給我了很多思路。

在後面的時間,藉著程式碼同步的思路,我又設想了雲 IDE 這個方案,本身程式碼同步的目的就是希望原生程式碼可以在遠端執行,那直接透過雲 IDE 開發,並直接執行服務,這樣執行的服務也是在遠端的,可以直接訪問。這個思路是沒問題的,但是按照目前大家的開發習慣,雲 IDE 不是長久之計,況且為了這個想法,開發一套雲 IDE,為了一口醋包了一頓餃子,可以,但沒必要∠( ᐛ 」∠)_。

之後又和有些同事聊前端開發的問題,聊到了這個想法,給我提供了一個新的思路,透過 whistle 代理和 webpack 外掛的方式,webpack 外掛以監聽模式打包,實時上傳編譯後的程式碼到遠端伺服器,whistle 代理用來解決除錯過程中的一些問題。當然這個方案是公司其他的同學在很早之前就已經開發出來了,名字叫 Carefree,不過現在已經不維護了,比較可惜。這個方案只能解決前端開發同學的需求,並且雲測平臺上我們對代理伺服器有些單獨的處理,不是很適合。

中間又過了一段時間,我設想了一下這個需求的最終形態,之前的方案都非常重,如果我做為使用者,可能就是在難用和難受之間徘徊(沒有說之前方案不好的意思,只是不適合這個需求...),我想它足夠的簡單和輕量,沒有什麼環境準備工作,拿來就能用。那最簡單的方式就是不在程式碼上面下功夫,而是轉向服務,只要維護好服務上的請求和響應,能夠和本地進行互動,就可以達到我想法中所要求的。這個時候,我的想法聚集到了一個方向——內網穿透。

市面上的內網穿透的應用有很多,這又涉及到了另一個問題,安全,如果內網穿透濫用的話,很可能會造成隔離的內網服務被對映到外網從而被攻擊,那損失就是把我賣了都賠不了...並且私下使用內網穿透本身也不好控制和追溯,有很大的安全隱患。

糾結了很長時間,既然不讓偷偷用,那就光明正大的用,我可以自己實現一個應用,只要限制好功能和安全邊界就可以了(已經和安全部門報備過了,放心)。而且自己實現,可以滿足自己的所有想法,輕量簡單,和雲測平臺結合等等,沒有什麼可以比實現自己的想法還令人激動的事情啦。於是便有了下面的內容。

localhost 是什麼

介紹

localhost 是一個使用 Go 語言編寫的輕量簡單的內網穿透工具。這個工具支援 web 服務的對映,會將啟動在本地 localhost 中的服務對映到遠端伺服器上,在訪問遠端對應的服務時,實際請求會利用本地和遠端已經建立的隧道傳送到本地服務中,達到訪問本地服務的目的。為什麼要使用 Go 來寫呢,相對於其他的語言,Go 編譯簡單且編譯完沒有額外的執行環境要求,本地交叉編譯可以得到各類系統的可執行檔案,對於使用者來說非常友好。

使用

幫助文件在這裡:localhost 幫助文件,可以在幫助文件裡或者在賽博雲測平臺的雲真機使用頁面內進行工具下載。

就如上面說到的,localhost 是輕量簡單的,使用方式非常簡單,它是一個獨立的可執行檔案,啟動的引數只有兩個,啟動方式如下:

# windows
localhost.exe -token xxxxxxxx -port xxxx

# mac
localhost -token xxxxxxxx -port xxxx

-token 這個引數是當次使用的 token,可以在賽博雲測平臺的雲真機使用頁面上申請,每次的有效期半小時。

-port 這個引數是當前本地啟動的服務的埠。

在設計客戶端這部分的時候,為了儘可能降低大家的使用門檻,特意將引數設計的儘可能少,port 埠引數是必不可少的,那為什麼還設計需要一個 token 引數呢,這個引數的初衷是為了識別使用者的身份,類似於 ssh 協議的 key,使得行為可追溯,後來利用 token 來控制使用行為,比如單次使用有效期等等。其他的引數在不影響功能和安全的前提下,都被我排除掉了,希望它使用足夠簡單。

原理

整體工具分為三個部分:服務端,客戶端,web 端。服務端和客戶端是進行服務對映的主要部分,包含了建立通道,通道轉發之類的邏輯。web 端提供了一些互動的介面,路由聚合代理轉發的處理。

核心邏輯

localhost 最核心的部分就是內網穿透,它是由服務端和客戶端共同完成實現的。眾所周知本地啟動的服務,只能本地或區域網內訪問到,遠端裝置無法訪問本地服務,但是本地的裝置可以訪問遠端的服務,透過本地訪問遠端時建立的隧道進行通訊,來達到遠端裝置能夠訪問本地服務的目的。

整體流程圖如下:

首先在伺服器中,啟動了 web 端部分的服務,是整體服務中的底層服務的排程部分,其中提供了一些 client 端呼叫的 web 介面以及使用者請求時的反向代理等功能,web 端服務是長期執行在遠端伺服器上,在下面會詳細說明這部分做了什麼。

client 端會分發給內部同學下載使用,在執行 client 端的時候,client 呼叫 web 的服務,啟動對應的 server 端,並且將相關引數資訊傳入,並返回給 client 端。

server 端啟動的時候,會啟動監聽兩個埠服務,一個是監聽使用者請求的埠,一個是監聽 client 端這邊的隧道連線埠,當 client 端主動發起和遠端伺服器進行連線時,透過當前這個連線打通通訊隧道,當使用者請求進來時,透過已經建立的通訊隧道,將請求報文轉發到本地 client 端。

client 端啟動完成,並且呼叫 web 端服務成功返回之後,client 端拿到相關資訊連線對應的 server 端,隧道建立成功之後,等待服務端轉發過來的請求資訊。當監聽到請求過來時,client 端會主動連線啟動的指定埠的本地服務,並且將請求報文轉發給當前的本地服務,同時,響應報文也會透過已有的鏈路原路返回,最終回到開始的請求方。

透過這種方式,就可以達到遠端訪問本地服務的目的,透過中轉伺服器進行服務的穿透,並且這種方式不需要使用者關注中間過程,只需要啟動提供的 client 端服務,使用簡單,基本沒有使用成本,不會影響程式碼。

路由聚合反向代理

使用過程中可能有的同學會有這樣一個疑問,在 client 端啟動完成之後,會返回顯示訪問的連結,為什麼訪問這個連結就可以直接訪問到自己本地的服務呢?在 client 端啟動時,會呼叫 web 端的介面服務,這個時候會記錄當前的使用者身份,並且在啟動 server 端時,將啟動的 server 埠與當前的使用者 erp 形成一個對映關係,並且根據當前這個 erp 建立一個反向代理的規則。在 web 端啟動的服務中,有一個監聽當前請求的服務,當任何地方訪問 web 端的服務時,會對訪問的路由進行監聽判斷,如果能匹配到已有連線的 erp 資訊,就會將當前訪問請求報文轉發到對應的 server 端服務中,然後 server 端再將請求轉發到對應的 client 端。

流程圖如下:

另外,在透過第一次透過聚合的 erp 路由訪問之後,會記錄當前訪問的 ip,將 ip 與 erp 對映關係也對應上,這樣,在後續的訪問中,路由可以不用攜帶 erp 資訊,也同樣能夠對映到當前自己的本地服務,這樣可以解決一些靜態資源的訪問路徑的問題,也可以用來解決 history 路由訪問的情況。

未來

history路由處理

當前端工程的路由採用的 history 模式的時候,在上述的 erp 聚合的路由就會出現 history 路由訪問不對的情況,雖然可以透過第一次訪問 erp 路由之後去除 erp 來訪問,但是總體來說還是會帶來一些困擾,後續計劃採用泛域名解析,去除路由上的處理,將使用者標識透過域名來解析,路由迴歸使用者原本的樣子,這樣不會造成額外的困擾和理解上的成本。

支援https

當前 localhost 工具在互動的過程中整體流程上還是 http 協議,目前只能透過把本地工程的 https 配置去除才能使用,但是和有的同學溝通下來發現有的工程中 https 請求是必須的,所以後續將會支援 https,後續設想在訪問時只要是 https 的請求,就預設訪問本地專案的 https,不需要額外的顯式配置或宣告。

結束

原生程式碼的遠端之路,在整個過程中經歷了很多方向,也產生了很多想法,最終誕生了 localhost 這個工具,在後續的時間會結合更多的場景,繼續完善這個工具,希望能夠讓大家在工作的過程中,多快好省。

作者:京東零售 謝天

來源:京東雲開發者社群 轉載請註明來源

相關文章