基于Node.js的http模塊搭建HTTP服務(wù)器
當(dāng)你第一次接觸工程化的項(xiàng)目時(shí),看到項(xiàng)目控制臺(tái)正在 building,過一會(huì)突然跳出一個(gè) URL 地址,你點(diǎn)開它居然是你剛寫好的網(wǎng)頁,好神奇。
當(dāng)你接后端同伴的接口時(shí),你把數(shù)據(jù)帶去,接口竟然給你返回 500 錯(cuò)誤;你去找后端,后端說這樣傳不行,你不知道為啥不行,反正按照他說的改完,返回 200 成功了。
有時(shí)候你的請(qǐng)求莫名其妙的就跨域了,后端說讓你們自己處理,你就找呀找解決方案。但是為什么會(huì)跨域?后端怎么配置的,你也不清楚。
終于有一天,你痛定思痛,決定痛改前非,一定要自己搭一個(gè) HTTP 服務(wù)器,徹底理清這里面的彎彎繞繞,從此拒絕被忽悠,拒絕做只聽命令的大頭兵。
但是話說回來了,怎么入手呢?
別急,這都給您備好啦。寫 HTTP 服務(wù)器需要后端語言,不用說,自然首選 Node.js。
下面我們基于 Node.js 的 http
模塊,一起搭建一個(gè)的 HTTP 服務(wù)器。
http 模塊
一個(gè)超簡單的 HTTP web 服務(wù)器的示例:
const http = require('http') const server = http.createServer((request, response) => { response.statusCode = 200 response.end('hello world') }) server.listen(3000)
這里引入了 http 模塊,提供了 createServer 方法,傳入一個(gè)回調(diào)函數(shù),創(chuàng)建了一個(gè)服務(wù)器。
現(xiàn)在把代碼寫進(jìn) index.js
,再超簡單的把它運(yùn)行起來:
$ node index.js
打開瀏覽器,輸入 http://localhost:3000
,就能看到網(wǎng)頁顯示的 hello world
了。
代碼剖析
http.createServer 方法的參數(shù)是一個(gè)回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)有兩個(gè)參數(shù) —— 它們是 HTTP 服務(wù)器的核心。
第一個(gè)參數(shù)是請(qǐng)求對(duì)象 request
,第二個(gè)參數(shù)是響應(yīng)對(duì)象 response
。你可以把它們看作兩個(gè)袋子,一個(gè)袋子里裝著請(qǐng)求相關(guān)的數(shù)據(jù),一個(gè)袋子里裝著響應(yīng)相關(guān)的操作。
request
包含了詳細(xì)的請(qǐng)求數(shù)據(jù),也就是我們前端調(diào)接口傳遞過來的數(shù)據(jù)。通過它可以獲取請(qǐng)求頭,請(qǐng)求參數(shù),請(qǐng)求方法等等。
response
主要用于響應(yīng)相關(guān)的設(shè)置和操作。什么是響應(yīng)?就是我收到了客戶端的請(qǐng)求,我可以設(shè)置狀態(tài)碼為 200 并返給前端數(shù)據(jù);或者設(shè)置狀態(tài)碼為 500 并返給前端錯(cuò)誤。
總之一句話,調(diào)用接口返回什么,是由 response
決定的。
事實(shí)上,createServer 返回的是一個(gè) EventEmitter,因此上面的寫法等同于這樣:
const http = require('http') const server = http.createServer() server.on('request', (request, response) => { response.statusCode = 200 response.end('hello world') }).listen(3000)
request 解析
用戶發(fā)起請(qǐng)求的相關(guān)數(shù)據(jù),都包含在 request 對(duì)象中。
這些數(shù)據(jù)包含常用的請(qǐng)求方法,請(qǐng)求頭,url,請(qǐng)求體等等數(shù)據(jù)。
const { method, url, headers } = request
method 表示請(qǐng)求方法可直接使用,headers 返回請(qǐng)求頭對(duì)象,使用也比較簡便:
const { headers } = request const userAgent = headers['user-agent'] // 請(qǐng)求頭全是小寫字母
唯獨(dú) url 字符串不好解析,里面包含了協(xié)議,hostname,path,query 等等。
所幸 Node.js 提供了 url
和 querystring
兩個(gè)模塊解析 url 字符串。
URL 解析
先看一個(gè) url 模塊的例子:
const url = require('url') // 解析url字符串 var string = 'http://localhost:8888/start?foo=bar&hello=world' var url_object = url.parse(string) // { protocol: 'http:', host:'localhost:8888', pathname: '/start', query: 'foo=bar&hello=world' }
看到了吧,url
模塊可以將一個(gè)完整的 URL 地址字符串,拆分成一個(gè)包含各部分屬性的對(duì)象。
但是美中不足,其他部分都解析出來了,唯獨(dú) query 還是一個(gè)字符串。
query
需要二次解析。怎么辦呢?這時(shí)候第二個(gè)模塊 querystring
出場了:
const querystring = require('querystring') // 解析query字符串 var string = 'http://localhost:8888/start?foo=bar&hello=world' var url_object = url.parse(string) // { query: 'foo=bar&hello=world' } var query_object = querystring.parse(url_object.query) // { foo: 'bar', hello: 'world' }
這下就完美了。用 url + querystring 組合,可以完整解析你的 URL。
請(qǐng)求體解析
對(duì)于 POST
或者 PUT
請(qǐng)求,我們需要接收請(qǐng)求體的數(shù)據(jù)。
這里請(qǐng)求體比較特殊,它不是一次性傳過來的數(shù)據(jù),而是通過 Stream
流的方式流式傳遞來的,因此要通過監(jiān)聽 data 和 end 事件一點(diǎn)點(diǎn)的接收。
獲取方法如下:
server.on('request', (request, response) => { let body = [] request.on('data', chunk => { // 這里的 chunk 是一個(gè) Buffer body.push(chunk) }) request.on('end', () => { body = Buffer.concat(body) }) console.log(body.toString()) })
response 設(shè)置
服務(wù)器收到客戶端請(qǐng)求,要通過 response 設(shè)置如何響應(yīng)給客戶端。
響應(yīng)設(shè)置,主要就是狀態(tài)碼,響應(yīng)頭,響應(yīng)體三部分。
首先是狀態(tài)碼,比如 404:
response.statusCode = 404
再有是響應(yīng)頭:
response.setHeader('Content-Type', 'text/plain')
最后是響應(yīng)體:
response.end('找不到數(shù)據(jù)')
這三部分也可以合在一起:
response .writeHead(404, { 'Content-Type': 'text/plain', 'Content-Length': 49 }) .end('找不到數(shù)據(jù)')
發(fā)送 http 請(qǐng)求
http 模塊除了接受客戶端的請(qǐng)求,還可以作為客戶端去發(fā)送請(qǐng)求。
發(fā)送 http 請(qǐng)求是指,在 Node.js 中請(qǐng)求其他接口獲取數(shù)據(jù)。
發(fā)送請(qǐng)求主要通過 http.request
方法來實(shí)現(xiàn)。
GET
下面是一個(gè)發(fā)送 GET 請(qǐng)求的簡單示例:
const http = require('http') const options = { hostname: 'nodejs.cn', port: 80, path: '/learn', method: 'GET' } const req = http.request(options, res => { console.log(`狀態(tài)碼: ${res.statusCode}`) res.on('data', d => { process.stdout.write(d) }) res.on('end', () => {}) }) req.on('error', error => { console.error(error) }) req.end()
使用 http.request 發(fā)送請(qǐng)求后,必須顯示調(diào)用 req.end()
來表示完成請(qǐng)求發(fā)送。
POST
與上面 GET 請(qǐng)求基本一致,區(qū)別是看請(qǐng)求體怎么傳:
const http = require('http') const options = { hostname: 'nodejs.cn', port: 80, path: '/learn', method: 'POST' } const body = { sex: 'man', name: 'ruims' } const req = http.request(options, res => { console.log(`狀態(tài)碼: ${res.statusCode}`) res.on('data', d => { process.stdout.write(d) }) res.on('end', () => {}) }) req.on('error', error => { console.error(error) }) req.write(JSON.stringify(body)) // 傳遞 body 參數(shù)寫法 req.end()
詭異之處
看到這里,如果你對(duì) nodejs 理解不深,可能會(huì)發(fā)現(xiàn)幾處詭異的地方。
比如,正常情況下 POST 請(qǐng)求傳遞 body
參數(shù)可能是這樣的:
var body = { desc: '請(qǐng)求體參數(shù)' } var req = http.request({ path: '/', method: 'POST', data: body })
而上面說到的正確姿勢(shì)是這樣的:
var body = { desc: '請(qǐng)求體參數(shù)' } var req = http.request({ path: '/', method: 'POST' }) req.write(JSON.stringify(body))
還有上面獲取請(qǐng)求體也是如此。不能直接通過 request.body
獲取,非得這樣:
let body = [] request.on('data', chunk => { body.push(chunk) }) request.on('end', () => { body = Buffer.concat(body) })
這幾處應(yīng)該是大家理解 http 模塊最困惑的地方。其實(shí)刨根問底,這不屬于 http 的難點(diǎn),而是 Node.js 中 Stream
流的特有語法。
事實(shí)上,http 模塊的核心 ——— request
和 response
都屬于 Stream
,一個(gè)是可讀流,一個(gè)是可寫流。
以上就是基于Node.js的http模塊搭建HTTP服務(wù)器的詳細(xì)內(nèi)容,更多關(guān)于Node.js搭建http服務(wù)器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Node.js使用http模塊實(shí)現(xiàn)后臺(tái)服務(wù)器流程解析
- Node.js?搭建后端服務(wù)器內(nèi)置模塊(?http+url+querystring?的使用)
- Node.js基礎(chǔ)入門之path模塊,url模塊,http模塊使用詳解
- node.js使用http模塊創(chuàng)建服務(wù)器和客戶端完整示例
- Node.js進(jìn)階之核心模塊https入門
- node.js中http模塊和url模塊的簡單介紹
- node.js 核心http模塊,起一個(gè)服務(wù)器,返回一個(gè)頁面的實(shí)例
- Node.js中Request模塊處理HTTP協(xié)議請(qǐng)求的基本使用教程
- Node.js 中 http 模塊的深度剖析與實(shí)戰(zhàn)應(yīng)用小結(jié)
相關(guān)文章
sublime text配置node.js調(diào)試(圖文教程)
下面小編就為大家分享一篇sublime text配置node.js調(diào)試(圖文教程),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-11-11Node?文件查找優(yōu)先級(jí)及?Require?方法文件查找策略
這篇文章主要介紹了Node文件查找優(yōu)先級(jí)及Require方法文件查找策略。文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09node.js利用socket.io實(shí)現(xiàn)多人在線匹配聯(lián)機(jī)五子棋
這篇文章主要介紹了node.js利用socket.io實(shí)現(xiàn)多人在線匹配聯(lián)機(jī)五子棋的操作方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05詳解express + mock讓前后臺(tái)并行開發(fā)
這篇文章主要介紹了詳解express + mock讓前后臺(tái)并行開發(fā),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06快速搭建Node.js(Express)用戶注冊(cè)、登錄以及授權(quán)的方法
這篇文章主要介紹了快速搭建Node.js(Express)用戶注冊(cè)、登錄以及授權(quán),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05