零基礎(chǔ)之Node.js搭建API服務器的詳解
零基礎(chǔ)之Node.js搭建API服務器
這篇文章寫給那些Node.js零基礎(chǔ),但希望自己動手實現(xiàn)服務器API的前端開發(fā)者,嘗試幫大家打開一扇門。
HTTP服務器實現(xiàn)原理
HTTP服務器之所以能提供前端使用的API,其實現(xiàn)原理是服務器保持監(jiān)聽計算機的某個端口(通常是80),等待客戶端請求,當請求到達并經(jīng)過一系列處理后,服務器發(fā)送響應數(shù)據(jù)給到前端。
平時大家通過Ajax調(diào)用API,即是發(fā)起一次請求,經(jīng)過服務器處理后,得到結(jié)果,然后再進行前端處理。如今使用高級編程語言,要實現(xiàn)服務器那部分功能已經(jīng)變得非常簡單,接下來我們了解一下使用Node.js如何實現(xiàn)。
什么是Node.js?它可以做什么?
Node.js是一個JavaScript的運行時(runtime),它提供了大量用JS與操作系統(tǒng)打交道的API,通過這些API,我們可以調(diào)用本地程序、讀寫磁盤、監(jiān)聽端口、發(fā)起網(wǎng)絡(luò)請求等,這足以開發(fā)出一個功能完善的Server。
前期準備
簡單介紹完Node.js,開始寫代碼之前,我們需要安裝Node.js,安裝詳細過程就不說明了,請大家Google或者百度。不同系統(tǒng)安裝過程不一樣,如果是Linux、Mac,會相對順利且遇到問題的可能性較低。
判斷安裝成功與否,windows下,在cmd中執(zhí)行node -v,Linux、Mac下,在shell中執(zhí)行node -v,正常輸出版本號說明安裝成功。
tips:
windows如果提示命令未找到,可能是未配置環(huán)境變量
實現(xiàn)簡單的Server
Node.js安裝成功,我們找個地方新建目錄my-server作為我們的存放代碼的地方,接下來所有的代碼都在該目錄下。首先,在my-server的目錄下新建文件index.js,用如下代碼實現(xiàn)一個簡單的Server:
// index.js
// 通過require獲取兩個node內(nèi)置模塊
const http = require('http');
const nUrl = require('url');
// '127.0.0.1'表明只有本機可訪問,'0.0.0.0'表示所有人可訪問
const hostname = '127.0.0.1';
const port = 3000;
// 通過http.createServer獲取一個server實例
// 其中(req, res) => {},在服務器每次接收到請求時都會被執(zhí)行
const server = http.createServer((req, res) => {
let method = req.method; // 客戶端請求方法
let url = nUrl.parse(req.url); // 將請求url字符串轉(zhuǎn)換為node的url對象
// 如果客戶端GET請求'/',會執(zhí)行這個分支里面的邏輯
if (method === 'GET' && url.pathname === '/') {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
return;
}
// 如果客戶端GET請求'/api/user',會執(zhí)行這個分支里面的邏輯
if (method === 'GET' && url.pathname === '/api/user') {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({
code: 0,
msg: '',
result: {
username: 'shasharoman'
}
}));
return;
}
// 沒有匹配其他分支的話,執(zhí)行以下邏輯
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Not Found');
});
// server開始監(jiān)聽,等待請求到來
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
文件內(nèi)容編輯保存后,在my-server目錄下通過命令node index.js啟動服務,然后在瀏覽器中訪問http://127.0.0.1:300/、http://127.0.0.1:300/api/user、http://127.0.0.1:300/xxx觀察不同結(jié)果。
這是官方Guides經(jīng)過小小修改得到的代碼,添加部分注釋以及額外邏輯。主要為了更清晰傳達以下幾個知識點:
- 從req對象上獲取method與url,這個req對象是客戶端請求的“抽象表現(xiàn)”,平時寫Ajax指定的絕大部分內(nèi)容都可以從該對象上獲取
- 中間添加的兩個if分支,主要是為了讓大家了解服務器如何區(qū)分不同請求,決定做不同事情,即路由概念
- Content-Type: application/json,通常API會使用的響應格式,表明返回數(shù)據(jù)是json格式,這是一個HTTP頭部,屬于HTTP協(xié)議相關(guān)知識
- statusCode:404,HTTP最常見的錯誤“Not Found”,也屬于HTTP協(xié)議相關(guān)知識
往前優(yōu)化一步
通過上面的代碼,實現(xiàn)了一個簡單Server,但真實場景下我們會這樣去實現(xiàn)嗎?答案是肯定不會,所以我們還需要一步步完善,做以下幾個修改:
- 增加config,在其中配置hostname,port
- 增加controller,用于分層以及分模塊
- 增加route,用于定義路由
代碼不多,一共五個文件:
- config.js,配置文件
- route.js,路由定義文件
- controller/account.js,賬號模塊業(yè)務實現(xiàn)文件
- controller/index.js,業(yè)務匯總并暴露給外部
- index.js,項目啟動文件
// config.js
exports = module.exports = {
hostname: '127.0.0.1',
port: '3000'
};
// route.js
exports = module.exports = [{
method: 'GET',
path: '/api/user',
impl: 'account.userById'
}, {
method: 'POST',
path: '/api/user',
impl: 'account.createUser'
}];
// controller/account.js
exports.userById = userById;
exports.createUser = createUser;
function userById(req, res) {
res.end('waiting for impl.');
}
function createUser(req, res) {
res.end('waiting for impl.');
}
// controller/index.js
exports.account = require('./account');
// index.js
const http = require('http');
const nUrl = require('url');
const config = require('./config');
const controller = require('./controller');
const route = require('./route').map(item => {
console.log(`route ${item.method}:${item.path}`);
let tuple = item.impl.split('.');
item.impl = controller[tuple[0]][tuple[1]];
return item;
});
const server = http.createServer((req, res) => {
let method = req.method;
let url = nUrl.parse(req.url);
let matchRoute = route.find(item => {
return item.method === method && item.path === url.pathname;
});
if (matchRoute) {
matchRoute.impl(req, res);
return;
}
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Not Found');
});
server.listen(config.port, config.hostname, () => {
console.log(`Server running at http://${config.hostname}:${config.port}/`);
});
依舊是用node index.js啟動Server,如果要在現(xiàn)有模式下開發(fā)一個API,主要就兩步:
- 在route.js中定義路由
- 在controller/中實現(xiàn)
做這個程度的優(yōu)化,只是為了向大家傳達一些比較寬泛的概念,還不是真正用來寫API服務,只是為了大伙練練手。
這個程度還達不到真實場景需求,還需要經(jīng)過幾輪改造,包括模塊、層、common、lib、query解析,body解析、更靈活的route等一系列事情,限于篇幅,有機會在一一講述。
經(jīng)過我的描述以及代碼示例,如果大家有興趣學習Node.js,建議多搜搜相關(guān)知識,保持關(guān)注,然后在逐步去熟悉Node.js流行的Web框架如:Express、Koa等,不過框架只是更高層面的封裝,基礎(chǔ)的概念以及知識還是需要花時間才能掌握。
如果前端想嘗試后端編程,請一定先學習HTTP協(xié)議,推薦《HTTP權(quán)威指南》從頭到尾認真看一遍。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
相關(guān)文章
使用node.js中的Buffer類處理二進制數(shù)據(jù)的方法
大家應該都知道在客戶端JavaScript腳本代碼中,對二進制數(shù)據(jù)并沒有提供一個很好的支持。然而,在處理TCP流或文件流時,必須要處理二進制數(shù)據(jù)。因此,下面通過這篇文章來一起看看利用node.js中的Buffer類處理二進制數(shù)據(jù)的方法,有需要的朋友們可以參考借鑒。2016-11-11
Nodejs+angularjs結(jié)合multiparty實現(xiàn)多圖片上傳的示例代碼
這篇文章主要介紹了Nodejs+angularjs結(jié)合multiparty實現(xiàn)多圖片上傳的示例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-09-09
用node擼一個監(jiān)測復聯(lián)4開售短信提醒的實現(xiàn)代碼
這篇文章主要介紹了用node擼一個監(jiān)測復聯(lián)4開售短信提醒的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
nodeJs實現(xiàn)基于連接池連接mysql的方法示例
這篇文章主要介紹了nodeJs實現(xiàn)基于連接池連接mysql的方法,結(jié)合具體實例形式分析了nodejs連接池操作mysql數(shù)據(jù)庫連接的實現(xiàn)與使用技巧,需要的朋友可以參考下2018-02-02
Node.js+jade抓取博客所有文章生成靜態(tài)html文件的實例
下面小編就為大家?guī)硪黄狽ode.js+jade抓取博客所有文章生成靜態(tài)html文件的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09

