nodejs 方便了咱們前端開發者進行一些服務端上的操做,能夠進行無縫地銜接。像其餘一些後端語言,如 php, golang, java 等,都須要必定的學習成本,而 nodejs 則就是爲前端開發者定製的。javascript
在 nodejs 中,提供了原生的 http 模塊,咱們能夠利用 http 模塊搞幾個經常使用的小工具,可以大大方便咱們的工做。php
我在以前從 0 到 1 學習 node(二)之搭建 http 服務器的文章中也講解過 http 模塊,不過咱們這裏主要是利用 http 模塊來打造幾個使用的工具。html
使用 nodejs 搭建 http 服務很是地簡單,只須要引入 http 模塊便可:前端
// server.js const http = require('http'); const ip = '127.0.0.1'; const port = 3000; http .createServer((req, res) => { res.end('heelo world!'); }) .listen(port, ip); console.log(`server has started at ${ip}:${port}`);
而後執行 server.js 文件:java
$ node server.js
在控制檯就會輸出:node
server has started at 127.0.0.1:3000
而後在瀏覽器上訪問http://127.0.0.1:3000
,就能看到hello world!的輸出。ios
若是想在啓動時,經過參數指定 IP 或端口。那麼咱們能夠經過process.env
來獲取命令行中指定的參數:git
// 經過process.env來獲取指定的參數 // 並設置兜底的數據 const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3000;
在執行 sever.js 時,就能夠經過參數指定 IP 和端口:github
$ PORT=3030 node app.js
在作開發和調試過程當中,常常須要考慮到一個請求或者圖片等加載很慢時,應該怎麼處理。golang
好比有用戶反饋某些圖片加載很慢,致使頁面看起來不正常。那麼我就應該針對圖片加載慢進行一些處理,但是怎麼模擬這個加載很慢的圖片呢?
不少現有的接口,都沒法模擬出這種有特殊延遲的狀況,這裏咱們可使用 http 模塊來實現。
咱們在第 1 個 http 服務器的基礎上,進行改進。
res.end()方法會告知服務器當前次響應結束,若沒有調用,則一直處於等待狀態。
咱們要實現一個有延遲的響應,可使用 setTimeout 延遲調用 end()方法便可。這裏先實現一個有延遲的接口。
http .createServer((req, res) => { const index = req.url.indexOf('?'); if (index >= 0) { const query = req.url.slice(index); const ss = new URLSearchParams(query); const timeout = ss.get('timeout'); const type = ss.get('type'); if (timeout && Number(timeout)) { return setTimeout(() => { if (type === 'json') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ code: 0, msg: 'hello world' })); } else if (type === 'image') { // 輸出本地一個圖片 } else { res.end(`delay ${timeout}ms response`); } }, Number(timeout)); } } res.end('hello world!'); }) .listen(port, ip);
想要延遲輸出圖片時,須要經過數據流的方式讀取本地的圖片,而後輸出到前端:
const stream = fs.createReadStream('./img/s.jpg'); const responseData = []; //存儲文件流 if (stream) { //判斷狀態 stream.on('data', function (chunk) { responseData.push(chunk); }); stream.on('end', function () { const finalData = Buffer.concat(responseData); // response.write(); res.writeHead(200, { 'Content-Type': 'image/jpg' }); res.end(finalData); }); }
咱們有時會遇到須要的接口存在跨域,或者是內網接口的問題,這時咱們就須要經過一箇中間層,來對接口進行中轉代理,才能正常地訪問接口。
實現接口代理時要注意亮點:
跨域的方式有不少種,好比 jsonp 也是其中一種,但 cors 跨域是比較好的一種,前端能夠有效地控制請求時間和取消請求。
在設置跨域頭Access-Control-Allow-Origin
時,這裏是不建議直接設置成*
。一方面是不安全,全部的域名均可以訪問;再有就是前端不會再傳送 cookie,沒法進行一些登陸態的校驗等。
在設置Access-Control-Allow-Origin
以前,咱們要先校驗下 headers 中的 referer,若是爲空或者不知足白名單的要求,則能夠直接返回 403。
const allowList = ['joke.qq.com', 'www.qq.com']; if (!req.headers || !req.headers.referer) { res.writeHead(403, 'forbidden'); res.end('403 forbidden'); return; } const { hostname } = new URL(req.headers.referer); if (!allowList.includes(hostname)) { res.writeHead(403, 'forbidden'); res.end('403 forbidden'); return; }
知足要求以後,須要將 referer 最後的斜槓/
去掉,不然會設置不成功。完成的代碼樣例以下:
const http = require('http'); const https = require('https'); const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3001; http .createServer((req, res) => { const allowList = ['joke.qq.com', 'www.qq.com']; if (!req.headers || !req.headers.referer || allow) { res.writeHead(403, 'forbidden'); res.end('403 forbidden'); return; } console.log('發起請求', req.headers); https .get('https://www.v2ex.com/api/topics/latest.json', (response) => { let data = ''; response.on('data', (chunk) => { data += chunk; }); response.on('end', () => { res.setHeader('Access-Control-Allow-Origin', (req.headers.referer || '').replace(/\/$/, '')); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); res.end(data); }); }) .on('error', (e) => { console.error(`請求遇到問題: ${e.message}`, e); res.end('error'); }); }) .listen(port, ip); console.log(`server has started at ${ip}:${port}`);
若須要代理更多的接口,或者路徑是從前端傳過來的,咱們本身卻是也能夠實現,不過還有更方便的 proxy 代理組件了。
這裏咱們用 http-proxy 組件來實現:
const http = require('http'); const httpProxy = require('http-proxy'); const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3000; const proxy = httpProxy.createProxyServer({ target: 'https://www.v2ex.com', // 代理的接口地址 changeOrigin: true, }); http .createServer((req, res) => { // 設置跨域頭 res.setHeader('Access-Control-Allow-Origin', (req.headers.referer || '').replace(/\/$/, '')); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); // 將請求和響應的對象傳給proxy proxy.web(req, res); }) .listen(port, ip);
而後前端直接按照路徑發起請求便可:
axios('http://localhost:3000/api/topics/latest.json').then(console.log).catch(console.error);
前端在寫頁面邏輯時,常常要考慮到數據的各類狀況,好比無數據時,長列表,各類長度的暱稱等。
不管是讀取配置的 json 文件,仍是用代碼生成的數據,都不具備隨機性。
如今,咱們能夠利用 mockjs 來實現各類數據的模擬:
const http = require('http'); const Mock = require('mockjs'); const ip = process.env.IP || '127.0.0.1'; const port = process.env.PORT || 3000; http .createServer((req, res) => { const result = Mock.mock({ code: 0, msg: 'success', 'x-from': 'mock', data: Mock.mock({ 'rank|20': [ { 'no|+1': 1, // no 字段從 1 開始自增 uin: () => Mock.Random.string(32), // 32 長度的隨機字符串 nick: () => Mock.Random.string(1, 20), // 長度在 1-20 之間的隨機字符串 face: () => Mock.Random.image('120x120'), // 120*120 的圖片 score: () => Mock.Random.integer(1, 2000), // 分數 }, ], }), }); res.setHeader('Access-Control-Allow-Origin', (req.headers.referer || '').replace(/\/$/, '')); res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(result, null, 2)); }) .listen(port, ip);
生成的數據:
關於 Mockjs 更多的語法規則,能夠訪問https://github.com/nuysoft/Mock/wiki/Getting-Started。
使用 nodejs 還能夠實現更多的功能,這裏咱們也僅僅是實現了其中簡單的幾個。基於咱們的前端知識和業務需求,咱們還能實現更多的小工具。
也歡迎您關注個人公衆號:「前端小茶館」