web學習:服務端開發的業務需求-路由解析

newbeehh發表於2018-06-25

後端(服務端)對於前端(客戶端)的來說就像是中轉站,後端呼叫底層(作業系統)服務上層(瀏覽器),而他們之間的橋樑便是IO流,後端與作業系統之間的是檔案IO流,與前端的便是網路IO流。這次,我們先探討下服務端與瀏覽器間的業務需求。

路由解析:

經過層層網路協議的解析,我們最終從瀏覽器請求中獲取到了相關資料。但如何處理這些資料呢,這就需要我們去解析請求的URL,並且分發相對應的處理邏輯。而URL的解析對映又分了多種方式。下面簡單介紹下。

  • 檔案路徑型:

這種解析方式就是URL路徑與網站的目錄的路徑一致,處理起來十分簡單,當我們的請求是獲取一個檔案,如html頁面時,簡單示意,如下:

const path=require('path');
const url=require('url');
const fs=require('fs');複製程式碼
function getFile(req,res,root) {
    //獲取url路徑
    var pathname=url.parse(req.url).pathname;
    fs.readFile(path.join(root,pathname),function (err,file) {
        res.end(file);
    })
}複製程式碼

當我們需要根據URL做不同業務邏輯處理時,也是尋找對應的檔案 ,如idnex.php,然後把它交給對應的指令碼解析器,並傳入HTTP上下文即可。記得很早之前學習PHP時,使用的Apache伺服器就是檔案路徑型的URL處理方式。

但使用nodeJs時,由於前後端檔案字尾都是.js,這樣就很難判斷哪個檔案是nodeJs的指令碼,哪個是前端指令碼,所以,得用另一種解析方式。

  • 手動對映型:

URL路徑和檔案路徑是沒有任何關係的,所以我們可以手動對映URL到對應的業務邏輯上,不用像檔案路徑一樣,每個url都得對應一個檔案,分發處理方面更加靈活方便。簡單示例:

//業務邏輯
function todo(req,res) {
    //TODO
}
//業務邏輯的集合
var routes=[];
//url對映
function use(path,action) {
    routes.push([path,action]);
}
//http請求響應入口程式。
function httpServer(req,res) {
    var pathname=url.parse(req.url).pathname;
    //分發業務
    for(var i=0;i<routes.length;i++){
        var route=routes[i];
        if(pathname===route[0]){
            var action=route[1];
            action(req,res);
            return;
        }
    }
}
//對映一個url
use('/user/todo',todo);複製程式碼

是不是很簡單,但我們還忽略了一點,那就是url引數,不同框架的標識不同,nodeJs的表示法是/todo/:params,就是冒號後面的那個值表示url傳遞的引數,所以我們使用手動對映時,就不能直接匹配字串了,得用正規表示式去解析url的引數出來,至於怎麼弄,好像真的有點複雜,具體就不演示了,大概知道就行。當然,還有url的查詢字串,就是?a=1&b=2這些,node的api有提供如何去獲取,這裡也不演示了。

手動對映的確很靈活,但專案過大的話,對映的路由也會變多過難以維護。而且查詢需要費時間,當然用map的話,時間可以縮短。所以還有另一種對映方式,無需去維護路由的對映。

  • 自動對映型:

就是事先約定好某個檔案中下儲存了某個路由的業務邏輯,如:url路是/controls/action/123,我們就約定好controls檔案對應路徑/controls,並且用controls檔案下action函式處理/controls/action,路徑剩下的便是該url的引數。簡單示例:

function httpServer(req,res) {
    var pathname=url.parse(req.url).pathname;
    var path=pathname.split('/');
    var controller=path[1];
    var action=path[2];
    var args=path.slice(3);
    var module=require(controller);
    module[action].apply(null,[req,res].concat(args));
}複製程式碼

是不是和檔案路徑對映有點像,其實原理都一樣的,具體細節上的不同這裡就不講了。接下來講下reslt。

  • reslt規範:

先說下它的全稱啊,Representational State Transfer(表現層狀態轉移),這句話具體什麼意思呢,我也不是很清楚哈,大概說下我從多篇文章中以及專案使用中獲得的理解吧。

reslt它是一種規範,什麼規範呢,就是將http的請求方法也加入路由的過程中。如我們是通過url的路徑來對映業務邏輯的,但如果遵循reslt規範,那就是判斷http的請求方法後,再結合url的路徑來對映對應的業務邏輯。而這就體現了reslt的設計思想,那就是通過url來設計資源,通過請求方法來定義資源的操作,通過accept請求欄位來決定資源的表現形式。

嗯,希望我的理解是正確的,一段簡單的示例程式碼:

var app={};
var routes={};
['get','put','delete','post'].forEach(function (md) {
    routes[md]={};
    app[md]=function (path,action) {
        routes[md].push([path,action]);
    }
});

function httpServer(req,res) {
    var pathname=url.parse(req.url).pathname;
    var method=req.method.toLowerCase();
    if(routes[method]){
        for(var i=0;i<routes[method].length;i++){
            var route=routes[i];
            if(pathname===route[0]){
                var action=route[1];
                action(req,res);
                return;
            }
        }
    }
}
app.get('/todo',function () {});
app.post('/todo',function () {});
app.delete('/todo',function () {});
app.put('/todo',function () {});複製程式碼

先寫到這兒,好累啊,本來想一次全寫完服務端的業務需求的,分批次來吧。


相關文章