從 PHP 轉到 Node.js 的那些事
如果你們開發團隊正在使用PHP,並考慮遷移到Node.js,這篇文章很適合你。本文並不探討從PHP移植到Node.js的細節,以及Node.js的基礎知識。而是涵蓋:決策制定、著手點的描述、編寫 Node.js 伺服器的深層次注意事項、以及部署策略。
為什麼遷移?
1stdibs 決定從 Apache/PHP 遷移到 Node.js+Express 有五個理由:
- 程式碼更少
- 全棧式JS
- 開發人員幸福度更高
- 投入回報率
- 未來的優化
程式碼更少
1stdibs基於面向服務體系架構(SAO),前端呼叫後臺的JAVA服務。這意味著需要同時維護前端模型,以及服務端PHP和客戶端JS模板。試想一下,如果可以擺脫PHP,就能夠統一前端展現與後臺模型於一種語言:JavaScript(同時可以合併一些模板)。從維護的角度來看,這麼做程式碼更簡潔,並且沒有重複邏輯。
全棧式JS(及其優點)
整個開發棧使用一種語言很簡便。對開發者來說,較少的環境切換使他們開心和高效。額外的好處是工具使用更簡單。相比之前使用Composer和npm兩個包管理器,現在只需要一個。儘管Composer很出色,由於nbp負責工具和客戶端管理,nbp總是必要的。一旦去掉所有的PHP程式碼,nbp將成為僅有的包管理器。
開發人員樂意
我們要保證開發人員的技能集得到擴充套件、職業生涯不斷髮展,這一點很重要。對於JavaScript工程師而言,Node.js極具吸引力。能夠在服務端使用與客戶端相同的工具、風格和模式,是非常順手和高效的。此外,Node.js相當流行,在企業級開發上也得到了長足發展
投入回報率
我們在招聘優秀的JS工程師和培訓初級JS工程師方面花了大價錢。由於客戶端棧很複雜,我們需要高階JavaScript工程師。我們不再僱用PHP工程師,僅僅僱用了JavaScript工程師。我們的觀點是,為什麼不培養他們在服務端的技能呢?
未來的優化
長遠而言,我們打算把兩個龐大的應用分割成一系列獨立部署的小應用。這很容易通過Node.js、Express和nbp實現。理論上,PHP(比如使用Slim)可以做同樣的事。但我們非但得不到上述好處,還會搞得一團糟:在Apache/PHP上進行操作會更加複雜,基礎設施也會變得有些奇怪。
選擇框架
那個最終被我們用Node.js替換掉的PHP應用,主要有如下職責:
- 登入和授權
- 路由選擇和服務端模板引擎(服務HTML)
- 引導前端應用
- 代理服務(為了迴避CORS)
- 服務靜態資源(js,css,images)
這些就是我們需要替換掉的基本功能。
我們嘗試過不少框架,Express令人歎為觀止(試一下我們評估過的spreadsheet)。任何未基於Express 的框架看起來都不靠譜。Express通俗易懂,並有良好的文件。另外,可以招聘到正經培訓過Express的人。
我們添加了一些kraken的核心模組(express-enrouten用於路由選擇、lusca負責安全);此外,i18n-node提供國際化支援,模板引擎使用Swig(我們後來放棄了Swig。呵呵,開源軟體還是有風險的)。
我們考慮過全盤使用kraken,但是從原來的服務端php模板引擎Twig切換到Swig直截了當,還很快捷。此外,kraken裡面的Dust和i18n也不討人喜歡。
編寫伺服器
選好了框架,下一步該寫伺服器了。
使用Apache+PHP時,你不需要再寫一個伺服器。Apache本身就是伺服器,PHP是應用。如果使用Node.js,伺服器和應用是同一個。從Apache/PHP轉到PHP,你需要處理一些之前自然而然使用的功能,這一點很重要。使用Apache,你(或者系統管理員)配置伺服器,在PHP應用裡完全不用關心Apache為你處理的那些事。Node.js卻以一種不同的方式來工作。
提供靜態檔案服務
毋庸置疑,提供靜態檔案服務是Apache的核心功能。Node.js與此不同,你要在應用中配置靜態檔案服務。幸運的是這很簡單,有良好的文件說明,並且是在Express中實現的。
日誌
很多基本的Apache配置為你提供訪問日誌和錯誤日誌。使用Node.js時,估計你也猜到了,同樣需要在應用中配置。所幸很多優秀的開源軟體包使之變得很簡單。Morgan是一個基本的請求日誌記錄器,它配置簡單,允許你把日誌寫到輸出流(標準輸出裝置或檔案)。如果你需要把日誌寫到資料庫,或者有別的(更高階的)日誌需求,那就試一下winston吧。
代理
我們有一個基本需求:能夠代理傳輸客戶端ajax請求到後臺服務。相比於處理CORS頭,代理所有來自相同域的請求要簡單得多。但你要想通過代理使用webpack-dev-server(正如我們所做的),就必須在Node.js應用中處理這一問題。http-proxy是一個簡單可靠的解決方案。
剩下的工作
除了上面提到的,還有一些列別的工作需要完成。我們從一個MVC應用談起,該應用基於 CodeIgniter(CI)框架,為一系列單頁應用提供服務。大部分工作就是移植:
- CI控制器移植到Express路由選擇器和中介軟體(包括登入和認證)
- Twig模板引擎移植到Swig(這一步比較瑣碎)
- Service層資料訪問(以便正常啟動客戶端單頁應用)
上面並未列出CodeIgniter模型這一關鍵元件。事實上根本不用重寫PHP模型!太給力了!我們的客戶端應用使用Backbone模型。當然這要擴充套件Backbone.Model.sync,從而使之全域性地工作在伺服器和客戶端。
部署
如果你的app規模較大,不應該一次性全部上線。可以通過漸進式部署的方式逐步上線。我們因此花費了好幾周。
漸進式部署的優點:
- 最小化bug範圍
- 每次在釋出一部分路由及功能的同時,其他工程師可以正常進行開發
- 對正在進行的功能開發和改進影響最小 — 新功能可以繼續釋出(這可能導致重複的工作)
- 如果操作得當,可以快速回滾到之前的服務
NGINX很不錯
該如何逐步上線呢?我們在眾多的伺服器中挑選了Nginx。
12345 | +----------+http||--->Apache/PHPrequest---->|Nginx|||--->Node.js+----------+ |
Nginx允許你一次只“開啟”一個路由(如果發現情況不妙就關掉 — 正如我們多次遇到的),這給了你很大的自由度。我們也發現開啟路由的時候不用部署程式碼,這很有幫助。這在一週一次的釋出計劃裡,為我們提供了一些迴旋空間。
不過有一個缺點,你需要確保客戶端程式碼同時接受舊的Apache/PHP伺服器和新的Node.js伺服器提供的服務。這並不可怕,不過你要把舊伺服器上未優化的功能移植到新的伺服器。屏住呼吸去做吧(記得寫一個便利貼去清理你的技術債)。
總結
從頭到尾,整個移植工作大概花費了一年。這聽起來可能有點荒謬,不過這個時間表包括決策過程(比較匆忙)、基於Express寫一個滿足需求的核心框架、移植所有功能、逐步漸進式上線。此外,請記住,我們始終只有一兩個開發者為之工作 — 並且是兼職。
如果你想嘗試一下,請慎重考慮。你的團隊能否受益?你的整個組織能否受益?如果你來自商業組織,請記住商業需要持續運轉。你需要在商業目標和工程目標之間找到良好的平衡。
我們很高興嘗試過。
相關推薦
從 PHP 轉到 Node.js 的那些事
如果你們開發團隊正在使用PHP,並考慮遷移到Node.js,這篇文章很適合你。本文並不探討從PHP移植到Node.js的細節,以及Node.js的基礎知識。而是涵蓋:決策制定、著手點的描述、編寫 Node.js 伺服器的深層次注意事項、以及部署策略。 為什麼遷移?
轉 node.js裏面的http模塊深入理解
abi 處理 -h image -1 dex 比較 nds highlight 問題1:HTTP服務繼承了TCP服務模型,是從connection為單位的服務到以request為單位的服務的封裝,那麽request事件何時觸發? 註意:在開啟keepalive後,一個TCP
[轉] node.js如何獲取時間戳與時間差
適合 但是 影響 and log http 處理 www. 系統資源 [From] http://www.jb51.net/article/89767.htm Nodejs中獲取時間戳的方法有很多種,例如: 1.new Date().getTime()
使用PHP和Node.js連線dubbo服務
使用PHP和Node.js連線dubbo服務 DUBBO是一個分散式服務框架,致力於提供高效能和透明化的RPC遠端服務呼叫方案,是阿里巴巴SOA服務化治理方案的核心框架,每天為2,000+個服務提供3,000,000,000+次訪問量支援,並被廣泛應用於阿里巴巴集團的各成
玩轉Node.js單元測試
程式碼部署之前,進行一定的單元測試是十分必要的,這樣能夠有效並且持續保證程式碼質量。而實踐表明,高質量的單元測試還可以幫助我們完善自己的程式碼。這篇部落格將通過一些簡單的測試案例,介紹幾款Node.js測試模組: Mocha和Should,SuperTest。本文側重於解釋原理,各個模組的詳細使用案例以後單獨
MAC 如何升級PHP版本 « 關於網路那些事...
通常,MACOS Sierra都會預設安裝PHP5.6版本 這裡針對升級到更高階PHP版本流程進行說明: 可以透過brew 或者 curl 兩種方式來安裝 Bre
從win7到win10的那些事~
為啥要換成win10?我之前可一直都是win7粉,在知乎上搜了一波win10的體驗之後,感覺相對於win7而言更好看更快,再加之現在win10對大部分軟體都相容了,所以就轉粉了,聽說**win10 LTSB長期
(轉)Node.js module.exports與exports
var 的區別 開發者 () 使用 不同 不用 構造 filename 本文轉自Node.js module.exports與exports 作者: chemdemo 折騰Node.js有些日子了,下面將陸陸續續記錄下使用Node.js的一些細節。 熟悉Node.js的童鞋
Node.js模擬發起http請求從非同步轉同步的5種方法
使用Node.js模擬發起http請求很常用的,但是由於Node模組(原生和第三方庫)提供裡面的方法都是非同步,對於很多場景下應用很麻煩,不如同步來的方便。下面總結了幾個常見的庫API從非同步轉同步的幾種方法。模組有:request, request-promis
從Node.js 轉到 Go平臺
在用 Node.js 建立了 Bowery 的第一個迭代版本後,我們在2014年2月切換到了 Go,我們的開發和部署速度也因此得到提升。從那以後,我們整個團隊都變成了專職的地鼠(譯者注:Go 的吉祥物)。Go 清晰明確的標準和更簡便的工作流程讓我們用 Go 用得很舒服。下面是我們熱愛用 Go 進行工作的原因,
Node.js的Buffer那些你可能不知道的用法
ins min 來看 imu write work and sse ase 在大多數介紹Buffer的文章中,主要是圍繞數據拼接和內存分配這兩方面的。比如我們使用fs模塊來讀取文件內容的時候,返回的就是一個Buffer: fs.readFile(‘filename‘, fu
(轉)Window 上安裝Node.js
自動 pda mysql setup back python .html 安裝步驟 修改 window上安裝nodejs非常的簡單,next,next就行了,環境變量都是自動配置,不明白為毛java不這樣 Window 上安裝Node.js http://www.runoo
【轉】Nodejs學習筆記(一)--- 簡介及安裝Node.js開發環境
ack 目錄 javascrip 難度 時間 網站開發 clas jetbrains 常用 目錄 學習資料 簡介 安裝Node.js npm簡介 開發工具 Sublime Node.js開發環境配置 擴展:安裝多版本管理器 學習資料 1.深入淺出Node.j
【轉】淺談Node.js單線程模型
包裝 傳遞參數 銷毀 img lba afr 第一個元素 request 浪費 Node.js采用 事件驅動 和 異步I/O 的方式,實現了一個單線程、高並發的運行時環境,而單線程就意味著同一時間只能做一件事,那麽Node.js如何利用單線程來實現高並發和異步I/O?本文將
從node.js模塊化開發來了解javascript閉包
js模塊 efi 使用 ict node cau class 無法訪問 完成 之前看過很多關於javascript閉包的解釋,只有短短幾個demo,一大段晦澀難懂的介紹,巴拉巴拉一大段閉包的概念,但是到最後也沒看懂閉包到底是什麽意思,起什麽作用,直到昨晚淩晨,我在學習n
實戰系列之 Node.js 玩轉 Java
liunx array github cal ddn 公眾 當前 eth pan 這些年以來,Node.js的興起,JavaScript已經從當年的“世界最被誤解的語言”變成了“世界最流行的語言”。且其發展之勢,從語言本身的進
從Github遠程庫安裝Node.JS
https 環境 登錄 新的 設置 幾分鐘 figure lib config 3)從Github遠程庫安裝Node.JS在這個方法中我們需要一些步驟來把Node.js的從Github上的遠程的倉庫克隆到本地倉庫目錄 在開始克隆(克隆)包到本地並且配制之前,我們要先安裝以下
JS 函數作用域及變量提升那些事!
向上 沒有 asc 程序 ole 理解 繼續 不知道 階段 一直以來小編對js函數作用域及變量提升的理論知識,雖然看了多次,但也是一知半解~ 這幾天做了幾道js小題,對這部分進行了從新的理解,還是有所收獲的~ 主要參考書籍: 《你不知道的JavaScript(上卷)》第
JS中數組那些事~
man ice 數組求和 尾刪 log var lte 數組 style 今天閑的沒事,看了一些關於數組的操作,好久木有用過,很多都已經忘記的差不多了,所以今天花了一個小時寫了一些demo,準備備份一下方便以後使用~~~ 下面是一些工作當中,經常用到的數組的方法,小
JS那些意想不到的操作(1)——數字帶尾數可以轉字符串
轉化 數字 class 活性 div 一個 ont 空字符 pan JS的靈活性一直是它的亮點,至於是優點呢還是缺點呢? 這個問題仁者見仁智者見智,JS總有一些令人意想不到的用法,這些用法雖不常見,卻足以引起重視。 就比如以下這種情況: 6.toString()