記最近一次Nodejs全棧開發經歷

背景:

前段時間大部門下新成立了一個推廣百度OCR文字識別圖像識別等科技能力在金融領域應用的子部門。由於部門剛成立,基礎設施和人力都是欠缺的。當時分到咱們部門的任務是抽調一我的作新部門主站前端開發工做。原本說的是隻負責頁面的開發工做。當我參加過需求品審會後,瞭解到新部門人力不足,而我今年主要任務又是在咱們部門作基於Nodejs的前端後端分離的架構升級工做。javascript

在這以前就是用Nodejs寫了兩個內部系統,並無大型的線上Web開發經驗,也想趁着這個機會鍛鍊下。而後就主動的跟老闆商量了這件事,老闆很是支持。以後又跟新部門的產品商量,原本就缺人手的他們也很是樂意我這邊承擔更多的開發任務。css

這篇文章和本身以前的文章的風格會有很大的區別,不會再去寫一些具體技術點和遇到問題的具體解決辦法,主要談的是我整個開發過程當中遇到的一些問題和思考解決他們的方法。html

內容列表

  • 技術選型的思考
  • 相關服務申請
  • 前端工程
  • 技術目標
  • Web安全
  • 內網機器訪問外網
  • 發送郵件
  • 網絡優化
  • 收穫

技術選型的思考

在文章的最開頭背景介紹中大概說了網站後端採用Nodejs的開發。爲了突出科技能力,網站要求了一些特效。由於我要用CSS3來寫這些特效,跟產品PK後結果是瀏覽器兼容性是IE8.0以上,特效知足大多數主流瀏覽器便可。那麼基於Nodejs的其它技術選型以下:前端

如下選擇這些技術的緣由:java

  • yog2(點擊到達主頁))是百度公司內部基於Express開發的比較成熟的Nodejs Web框架。提供的能力都是跟公司內部的基礎服務(同機房訪問、運維、日誌等)接軌的,並且有一些部門已經在線上大規模使用,若是遇到問題能夠有不少經驗能夠借鑑。
  • swig是yog2默認支持的模板引擎。
  • 由於Nodejs的語法是遵循CMD規範的。並且在百度內部提倡的也是使用FIS3和Mod.js。因此就選擇了公司內部的FIS3點擊到達主頁)和Mod.js點擊到達主頁)。FIS3不只有百度本身內部在用,也有不少的外部公司在用,好比滴滴等。
  • 由於交互要求兼容一些低版本瀏覽器和一些奇葩的國產瀏覽器。爲了保證開發時間的可控就選擇了本身熟悉的jQuery;

相關服務的申請

肯定了技術選型以後就是開始申請服務,主要包括如下相關內容:node

  • 域名申請
  • 服務器申請
  • Mysql數據庫申請
  • bos存儲服務(使用的是百度雲的bos存儲)

以上都是走的公司的內部流程,具體的就不介紹了。主要介紹下一些服務的做用。一個在網絡上運行的網站確定是須要一個域名的,能讓網站跑起來很定是須要線上服務器的。存儲用戶的註冊數據須要數據庫。由於使用OCR進行人臉識別,要知足識別一張圖片上的多張臉。是須要對用戶的圖片裁切。由於網站是部署在多臺機器上,確定不能存儲在網站運行的服務器上須要將裁切好的圖片存儲在專門的存儲服務器上,而且返回給網站圖片連接,mysql

前端工程

使用Nodejs開發的話,前端的工程的概念可能還要廣一些會涉及到Nodejs相關的工程化。這部分分兩部分介紹:git

1.前端

目標:github

  • 將不一樣頁面的公共模塊開發成組件,以方便在不一樣頁面間進行引用;
  • 使用 SASS 來作css的模塊化管理,而且實時編譯成css,生成map文件便於本地調試;
  • 將使用 CMD 規範編寫的組件和模塊化的代碼打包編程供頁面的業務代碼引用;
  • 給須要加廠商前綴的css屬性自動加廠商前綴;
  • 可以實時的將代碼部署到測試環境,以方便QA測試;

以上的這些目標均可以使用 FIS3和相關插件來實現。web

拆分公共模塊爲組件

當咱們觀察一個頁面的時候能夠發現一個頁面的這幾塊是不一樣頁面間能夠公用的。我把這些頁面的jscss(scss)html(tpl)寫在一個目錄以方便管理他們。就是我沒一次一次就能夠在全部頁面應用本身的修改。

組織組件的目錄:

當我在不一樣頁面間使用相同的navfooter的時候,只須要include一次就能夠了。

2.後端

由於咱們線上大規模使用的Nodejs版本是6.x版本。可是開發過程當中處理異步又是使用asyncawait。因此須要藉助編譯引擎將這些es7的語法編譯成6.x支持的語法。

另外就是藉助process.env.NODE_ENV能夠讀取環境變量的特性,來區分配置一些線上和線下的配置,好比:

const YOG_DEBUG = process.env.YOG_DEBUG;
const PANSHI_DEBUG = process.env.PANSHI_DEBUG;

let mysqlConf;

if (PANSHI_DEBUG === 'true') {
    mysqlConf = {
        host: '10.00.00.00',
        user: 'ppui',
        password: 'ppui',
        database: 'excel',
        port: '5003'
    };
} else if (YOG_DEBUG === 'true') {
    mysqlConf = {
        host: '127.0.0.1',
        user: 'root',
        password: '',
        database: 'pass_panshi',
        port: '3306'
    };
}

技術目標

這裏主要談一些前端的技術目標

1.樣式顯示和dom操做分離

以前開發過程當中常常遇到的狀況是我須要該一個html節點的樣式,不當心改了class類名。而js又偏偏使用了這個class操做了dom。這個時候頁面運行的時候確定會報錯的,增長了項目的維護成本。

有兩種方案能夠有效的解決這種問題,第一就是添加自定義屬性,好比<div class="section" node-type="pagesecond"></div>當我須要操做dom的時候就經過jQuery的屬性選擇器來操做這個dom而不會去使用class。這樣在我調整樣式、須要修改class名稱的時候也不會影響js代碼。第二種就是根據你們常常說的使用-來作html 類名的鏈接符,而咱們就規定一個規範就是使用下劃線(_)來標記我要操做dom節點的名稱,好比<div class="section _pagesecond"></div>

這兩種方式,若是是在開發多人維護的項目是都是須要提早預約規範,我在項目中是使用的前者。

2.業務代碼和功能代碼分離

在前面已經介紹過就是使用cmd規範來組織前端代碼。好比爲了可以知足我使用屬性選擇器來做爲操做dom的需求。我特意本身封裝了一些代碼段,好比在base.js文件中有一段這樣的代碼:

/**
 * 根據node-type獲取節點信息
 *
 * @param {any} params 獲取節點元素
 * @param {any} context 上下文環境
 * @returns
 */
exports.nodeTypeDom = function (params, context) {
    if (context && context !== '') {
        return $('[node-type="' + params + '"]', $('[node-type="' + context + '"]'));
    } else {
        return $('[node-type="' + params + '"]');
    }
};

我在其餘文件中須要使用這個代碼段的時候,只須要像下面這樣就能夠了。

var baseJs = require('../libjs/base');
var node = baseJs.nodeTypeDom;

// 須要選擇 dom 的地方,直接傳入自定義屬性的值

node('pagesecond').xxxx

除了一些經常使用的代碼段這樣封裝,一些組件也按照這樣的方式封裝。好比:輪播圖組件、文件上傳組件、表單校驗組件、tab滾動組件。

以上兩種方式的好處都可以極大的提升代碼的可維護性、閱讀性。

Web安全

我在開發過程當中關注的Web安全主要是

  • sql注入
  • 接口攻擊

1.防範sql注入

sql注入簡單些說就是指一些違法用戶拼接一個特殊的用戶名或者是密碼,由於咱們要把用戶名和密碼插入數據庫,確定會根據這個用戶名和密碼拼接一個sql語句。而違法用戶的這個特殊用戶名語句有可能刪掉咱們數據庫的全部數據。

由於使用的是mysql數據庫。Nodejs模塊使用的也是npm上使用最多的Mysql模塊。自己這個模塊已經提供了訪問mysql集羣的能力和防注入的能力。

具體方法能夠參考官方文檔點擊這裏直達

2.防範接口攻擊

這裏要作的就是有些違法用戶拿到咱們接口的時候,寫一個循環頻繁的訪問咱們的接口。爲了防止有些違法用戶就是給請求加token。就是在向服務端發起請求的時候返回給前端的一個token,前端請求後端的時候帶上這個token。若是token在後端校驗經過就銷燬這個token 。還有好比驗證請求的源IP,這裏注意的是咱們驗證IP的時候應該獲取的是HTTP協議header字段中的x-forwarded-for屬性的值。(這兩種方法能夠一塊兒使用)

不事後來從後端RD那邊瞭解到公司有專門的服務能夠用來作反做弊,並且策略更全面些。目前在研究準備接入。

內網機器訪問外網

關於跨機房訪問、同機房訪問和內網訪問外網,這些基本上都會涉及到運維的話題。百度內部有現成的服務接入文檔。各個公司可能提供能力的方式不同。這裏很少介紹。

這裏談一些小的細節點。先看下面的一張圖:

一句話總結:當一條請求到達接入層以前是不知道要訪問內網環境下那個機房的服務器的。相反的內網的機器上若是有一條請求外網的連接,好比:http://weibo.com 。須要經過一個proxy訪問外網服務器。

訪問接口我使用request模塊。配合promise npm上有request-promise由名字咱們就知道他的每一個方法或者是調用結果返回的是什麼了。這個模塊默認已經提供了代理參數的相關配置。具體的能夠參考文檔點擊直達

這裏涉及的知識比較多,好比代理隧道、https請求的代理。在閱讀官方配置文檔的時候搜索一些關鍵字瞭解一些其它相關知識便可。

若是有相關的需求,能夠參考個人配置,若是個人配置不能解決你的問題,請仔細閱讀官方文檔哈。、

let options = {
        'url': params.url,
        'encoding': 'binary',
        'rejectUnauthorized': false   // 取消https證書的校驗
    };

    // 解決代理https請求的行爲 測試機須要配置環境變量 PANSHI_HTTPS_PROXY
    if (process.env.PANSHI_DEBUG !== 'true' || PANSHI_HTTPS_PROXY) {
        options.tunnel = false;
        options.proxy = 'http://xxxx.proxy.com:8080';
    }

發送郵件

到這裏關於開發相關介紹已經完畢。這裏介紹的就是運營和產品需求的一些功能開發。天天將註冊的用戶發送給相應的責任人。

若是要知足這個功能須要有郵件服務器。這個在公司內部有公用的能夠很容易找到。其它就是配置服務的crontab定時執行腳本查詢數據庫發送郵件。

這裏主要使用了nodejs模塊nodemailer。具體的相關配置和發送郵件的方法能夠參考官方文檔配置點擊直達

網絡優化

  • 靜態文件cdn部署;
  • 合併靜態文件;
  • 緩存靜態文件;
  • icon使用Base64

上面列舉的是比較典型的幾個點。好比像css放head標籤頭部,script標籤放到body標籤底部。這些應該屬於一個前端工程師的常識吧。

靜態文件部署CDN這個很少介紹,每一個公司都會本身的一套方法。這裏主要介紹下合併靜態文件和緩存靜態文件。

1.合併靜態文件

默認FIS3是有插件支持合併靜態文件的。由於我此次開發的頁面較多(總共11個主站頁面),且由於採用的分塊開發加載模塊和靜態文件。若是不作合併的話,一個頁面加載完須要有10-20條的靜態文件的請求。會影響頁面的加載速度。

當我準備使用FIS3的插件來合併靜態文件的時候發現仍是有些麻煩的須要一個頁面一個頁面去配置要打包合併的靜態文件。最後請教了下其它部門的同事使用咱們接入層服務器提供的comb功能,由服務器幫咱們合併靜態文件(其實就是Nginx 的concat模塊提供的功能)。這裏也不作過多的介紹,自行搜索文章瞭解就能夠了。

2.緩存靜態文件

先來看下一張圖

上圖中紅色框出來的都是跟靜態文件緩存有關的http協議的字段。若是對這些字段的概念比較模糊能夠閱讀這篇文章加深下印象《HTTP緩存》點擊直達

無論使用express仍是koakoa可使用koa-static-cache中間件)都用相應的靜態文件服務的中間件提供配置這幾個字段的能力。express能夠經過一下方式配置(具體的能夠閱讀express文檔)

const express = require('express')

// 配置與靜態文件相關的參數
express.static('xxxxx')

收穫

最後就是談談此次開發的收穫

  • 這個項目開發上線之後,恰好到了大部門的年中總結會,由於本身獨立負責了先後端的開發工做,得到了大部門的「閃耀之星」獎勵和一些物質獎勵(雖然還沒見到影??)。
  • 對公司內部申請相關服務流程的熟悉和使用這些服務的方法,以及對整個公司後端服務體系的瞭解;
  • 此次開發仍是遇到不少坑的,也被別人說過代碼寫的「爛」,但我以爲最主要的緣由就是不具備後端思惟吧。想寫好Nodejs就是用後端思惟去寫Nodejs,這個須要多寫,多踩坑。

在這個過程經歷的好多事情,心態上也是考驗。既然下決心作一件事情了,本身不放棄本身,就沒有人可以有放棄本身。

相關文章
相關標籤/搜索