利用node js快速類比Web API

來源:互聯網
上載者:User

標籤:

Web API即使通過網路進行調用的API介面,與具體的程式設計語言無關。現在常見的是通過標準的HTTP GET/POST請求,從伺服器擷取響應的資源或服務,伺服器返回調用的結果內容,一般為xml格式或者json格式的資料(現在使用json的更多)。

在開發App的時候,一般原型設計好(如使用just in mind之類的工具)之後,我們會設計出與伺服器互動的介面文檔。一般情況下,App的開發進度(尤其原型)要快於伺服器的開發進度。在App靜態原型開發完到伺服器實現所有的互動介面這段期間內,我們當然不能閑著。這時,我們可以本地類比一個HTTP伺服器,從而可以繼續App的”動態化”開發。

由於對javascript比較熟悉,簡單看了一下node js之後,就使用它來開發本地的HTTP伺服器並提供各種互動的介面。這裡記錄一下是怎麼一步一步實現的。

一步一步實現HTTP伺服器

樣本起見,杜撰了3個介面(無論多少個,原理都一樣),如下:

焦點圖/sample_app/focus_pic文章列表/sample_app/article_list文章詳情/sample_app/article_detail

我們可以將伺服器劃分為以下幾個模組:

  1. 入口 - app.js,總體管理伺服器。一般是啟動伺服器
  2. server模組 - server.js,負責伺服器的配置與請求的轉寄。如伺服器監聽的連接埠,請求日誌的記錄,請求轉寄至具體的處理函數等
  3. router模組 - router.js,顧名思義,負責請求的路由功能。例如,我們在這裡可以將不同的請求地址轉寄至不同的函數處理。
  4. request handlers模組 - request_handler.js,針對每個請求進行處理的函數都定義在這個模組裡邊。
  5. response template模組,由於我們只是快速類比提供Web API服務的HTTP伺服器,所以真正返回的內容寫在模板裡邊即可。

其實3個介面的路由(將不同的請求轉到對應的處理函數)按照道理應該在router模組中進行處理,但是因為針對每個介面的處理邏輯都是相同的,只是返回的內容不同,我就把路由邏輯轉到request handlers模組中去了。具體如何寫,可以根據實際的情況進行調整,這裡邊只是提供一個思路而已。

單看文字還是比較晦澀的,我們來看一下具體的代碼:
server.js

/** * Created by FIMH on 2016/05/05. */var http = require(‘http‘);var url = require(‘url‘);function start(route, handle) {    function onRequest(request, response) {        // 擷取請求路徑        var parsedUrl = url.parse(request.url);        var pathname = parsedUrl.pathname;        console.log(‘Request for ‘ + pathname + ‘ received.‘);        route(handle, parsedUrl, request, response);    }    http.createServer(onRequest).listen(9999);    console.log(‘Server has started.‘);}exports.start = start;

可以看到,主要配置了HTTP伺服器監聽的連接埠 - 9999,以及列印了一條log資訊,然後將請求轉至router模組進行處理

router.js

/** * Created by FIMH on 2016/05/05. */// 針對不同的請求,做出不同的相應function route(handler, parsedUrl, request, response) {    var pathname = parsedUrl.pathname;    console.log(‘About to route a request for ‘ + pathname);    // 禁止訪問favicon.ico    if (!pathname.indexOf(‘/favicon.ico‘)) {        return;    }    // 這裡不用檢查請求路徑是否正確,將路由放到handle對應的函數中去    handler(parsedUrl, request, response);}exports.route = route;

這裡我們主要攔截了對favicon.ico檔案的訪問,關於這個檔案是什麼,大家可以自行搜尋。
前面也提到了,由於這個sample裡邊,每個介面的處理邏輯都是相同的,只是返回的內容不同,我就把路由邏輯轉到request handlers模組中去了。

真正的處理邏輯都在下面這個模組中
requests_handlers.js

/** * 請求處理入口。 */function handleRequests(parsedUrl, request, response) {    // 解碼並解析querystring    //var queryStringUtil = require(‘querystring‘);    //var queryString = parsedUrl.query;    //var queryStringResultObject = queryStringUtil.parse(queryString);    var pathname = parsedUrl.pathname;    // 在這裡進行處理}exports.handleRequests = handleRequests;

這裡,我只貼了一個請求處理的入口函數。
在這個地方我重構了一次,最初的處理邏輯大致如下:

    var templateName;    var innerHtml;    if (pathname == ‘/sample_app/focus_pic‘) {       templateName = ‘focus_pic‘;    } else if (pathname == ‘/sample_app/article_list‘) {        templateName = ‘article_list‘;    } else if (pathname == ‘/sample_app/article_detail‘) {        templateName = ‘article_detail‘;        innerHtml = ‘article‘;    }    if (templateName) {        handleValidRequest(request, response, templateName, innerHtml);    } else {        handleErrorOutput(request, response, 400, ‘Invalid request url!‘);    }

因為這裡只是3個請求,看著還不明顯,如果比較多了,那麼if…else寫起來就太煩了,這時候我想起來好多js語言的項目(如cocos 2d-js,egret)都會使用json檔案作為項目的設定檔,依次來簡化代碼並提高靈活性。

這時,我們可以定義一個項目的設定檔,我這裡取名叫appProperties.json,內容如下

{  "route": {    "/sample_app/focus_pic": {      "template": "focus_pic"    },    "/sample_app/article_list": {      "template": "article_list"    },    "/sample_app/article_detail": {      "template": "article_detail",      "inner_html": "article"    }  }}

然後我們修改前面提到的模組 - requests_handlers.js
先定義一個全域變數var routeObj;
然後在函數handleRequests裡這樣處理:

// 解析route配置資訊    if (!routeObj) {        var fs = require(‘fs‘);        var propertiesPath = ‘./appProperties.json‘;        var propertiesData = fs.readFileSync(propertiesPath, ‘utf-8‘);        routeObj = JSON.parse(propertiesData);    }    var templateObj = routeObj[‘route‘][pathname];    if (templateObj) {        handleValidRequest(request, response, templateObj[‘template‘], templateObj[‘inner_html‘]);    } else {        handleErrorOutput(request, response, 400, ‘Invalid request url!‘);    }

重構之後,無論介面有多少個,處理的代碼依然是這幾行;而重構前的方法,每添加一個介面,都需要增加一個 else if
拿演算法複雜度的概念來比對,重構前就是O(n),而重構後則為O(1)。

關於response template模組的處理,這裡就不貼代碼了。主要是使用node js同步或者非同步讀模數板檔案,還有對json對象的序列化,編輯與還原序列化。大家有興趣的話可以看整個sample的原始碼,見文章底部。

總結與原始碼

如果使用傳統的方式,你需要安裝一個http伺服器 - 如apache,還有一個語言處理模組 - 如php。
而使用了node js之後,你只需要安裝一個node運行時,剩下的http伺服器,請求解析,處理,返回等全部使用js來進行編寫即可,而且書寫的代碼量也很小。

整個項目的代碼我放到github上了,詳見nodejs_sample_app

利用node js快速類比Web API

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.