<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          什么時候,你想寫一個 HTTP 服務(wù)器?

          共 4851字,需瀏覽 10分鐘

           ·

          2022-01-19 17:12


          曾幾何時,作為前端的你,想要寫一個 HTTP 服務(wù)器?

          當(dāng)你第一次接觸工程化的項目時,看到項目控制臺正在 building,過一會突然跳出一個 URL 地址,你點開它居然是你剛寫好的網(wǎng)頁,好神奇。

          當(dāng)你接后端同伴的接口時,你把數(shù)據(jù)帶去,接口竟然給你返回 500 錯誤;你去找后端,后端說這樣傳不行,你不知道為啥不行,反正按照他說的改完,返回 200 成功了。

          有時候你的請求莫名其妙的就跨域了,后端說讓你們自己處理,你就找呀找解決方案。但是為什么會跨域?后端怎么配置的,你也不清楚。

          終于有一天,你痛定思痛,決定痛改前非,一定要自己搭一個 HTTP 服務(wù)器,徹底理清這里面的彎彎繞繞,從此拒絕被忽悠,拒絕做只聽命令的大頭兵。

          但是話說回來了,怎么入手呢?

          別急,這都給您備好啦。寫 HTTP 服務(wù)器需要后端語言,不用說,自然首選 Node.js。

          下面我們基于 Node.js 的 http 模塊,一起搭建一個的 HTTP 服務(wù)器。

          http 模塊

          一個超簡單的 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 方法,傳入一個回調(diào)函數(shù),創(chuàng)建了一個服務(wù)器。

          現(xiàn)在把代碼寫進(jìn) index.js ,再超簡單的把它運行起來:

          $?node?index.js

          打開瀏覽器,輸入 http://localhost:3000,就能看到網(wǎng)頁顯示的 hello world 了。

          代碼剖析

          http.createServer 方法的參數(shù)是一個回調(diào)函數(shù),這個回調(diào)函數(shù)有兩個參數(shù) —— 它們是 HTTP 服務(wù)器的核心。

          第一個參數(shù)是請求對象 request,第二個參數(shù)是響應(yīng)對象 response。你可以把它們看作兩個袋子,一個袋子里裝著請求相關(guān)的數(shù)據(jù),一個袋子里裝著響應(yīng)相關(guān)的操作。

          request 包含了詳細(xì)的請求數(shù)據(jù),也就是我們前端調(diào)接口傳遞過來的數(shù)據(jù)。通過它可以獲取請求頭,請求參數(shù),請求方法等等。

          response 主要用于響應(yīng)相關(guān)的設(shè)置和操作。什么是響應(yīng)?就是我收到了客戶端的請求,我可以設(shè)置狀態(tài)碼為 200 并返給前端數(shù)據(jù);或者設(shè)置狀態(tài)碼為 500 并返給前端錯誤。

          總之一句話,調(diào)用接口返回什么,是由 response 決定的。

          事實上,createServer 返回的是一個 EventEmitter,因此上面的寫法等同于這樣:

          const?server?=?http.createServer()

          server.on('request',?(request,?response)?=>?{
          ??response.statusCode?=?200
          ??response.end('hello?world')
          })

          request 解析

          用戶發(fā)起請求的相關(guān)數(shù)據(jù),都包含在 request 對象中。

          這些數(shù)據(jù)包含常用的請求方法,請求頭,url,請求體等等數(shù)據(jù)。

          const?{?method,?url,?headers?}?=?request

          method 表示請求方法可直接使用,headers 返回請求頭對象,使用也比較簡便:

          const?{?headers?}?=?request
          const?userAgent?=?headers['user-agent']?//?請求頭全是小寫字母

          唯獨 url 字符串不好解析,里面包含了協(xié)議,hostname,path,query 等等。

          所幸 Node.js 提供了 urlquerystring 兩個模塊解析 url 字符串。

          URL 解析

          先看一個 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 模塊可以將一個完整的 URL 地址字符串,拆分成一個包含各部分屬性的對象。

          但是美中不足,其他部分都解析出來了,唯獨 query 還是一個字符串。

          query 需要二次解析。怎么辦呢?這時候第二個模塊 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。

          請求體解析

          對于 POST 或者 PUT 請求,我們需要接收請求體的數(shù)據(jù)。

          這里請求體比較特殊,它不是一次性傳過來的數(shù)據(jù),而是通過 Stream 流的方式流式傳遞來的,因此要通過監(jiān)聽 dataend 事件一點點的接收。

          獲取方法如下:

          let?body?=?[]
          request.on('data',?chunk?=>?{
          ??//?這里的?chunk?是一個?Buffer
          ??body.push(chunk)
          })
          request.on('end',?()?=>?{
          ??body?=?Buffer.concat(body)
          })

          response 設(shè)置

          服務(wù)器收到客戶端請求,要通過 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 請求

          http 模塊除了接受客戶端的請求,還可以作為客戶端去發(fā)送請求。

          發(fā)送 http 請求是指,在 Node.js 中請求其他接口獲取數(shù)據(jù)。

          發(fā)送請求主要通過 http.request 方法來實現(xiàn)。

          GET

          下面是一個發(fā)送 GET 請求的簡單示例:

          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ā)送請求后,必須顯示調(diào)用 req.end() 來表示完成請求發(fā)送。

          POST

          與上面 GET 請求基本一致,區(qū)別是看請求體怎么傳

          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()

          詭異之處

          看到這里,如果你對 nodejs 理解不深,可能會發(fā)現(xiàn)幾處詭異的地方。

          比如,正常情況下 POST 請求傳遞 body 參數(shù)可能是這樣的:

          var?body?=?{?desc:?'請求體參數(shù)'?}
          var?req?=?http.request({
          ??path:?'/',
          ??method:?'POST',
          ??data:?body
          })

          而上面說到的正確姿勢是這樣的:

          var?body?=?{?desc:?'請求體參數(shù)'?}
          var?req?=?http.request({
          ??path:?'/',
          ??method:?'POST'
          })
          req.write(JSON.stringify(body))

          還有上面獲取請求體也是如此,不能直接通過 res.body 獲取,非得監(jiān)聽事件,然后拼接數(shù)據(jù)。

          這幾處應(yīng)該是大家理解 http 模塊最困惑的地方。其實刨根問底,這不屬于 http 的難點,而是 Node.js 中 Stream 流的特有語法。

          事實上,http 模塊的核心 ——— requestresponse 都屬于 Stream,一個是可讀流,一個是可寫流。

          因此,徹底理解 http 模塊,還需要深入了解 Stream 流的相關(guān)知識。

          總結(jié)

          本篇基于最基礎(chǔ)的 http 模塊搭建了簡單的 HTTP 服務(wù)器,并且實現(xiàn)了簡單的接收請求發(fā)送請求。

          不過呢,真正的應(yīng)用場景一般不會這么搭。社區(qū)有成熟穩(wěn)定的 express 框架更適合寫 Node.js 服務(wù);發(fā)送請求,可以用我們最熟悉的 axios ?——— 沒錯,axios 也可以在 Node.js 中使用。

          但是你可能不知道,express 和 axios 的核心功能,都是基于 http 模塊。

          因此,基礎(chǔ)很重要。地基不牢,地動山搖。當(dāng)你在 express 中見到 Stream?的用法時,也不至于不明所以。

          這篇就到這里,下一篇我們繼續(xù)探索 Stream 流,記得關(guān)注我哦。


          往期干貨

          ?26個經(jīng)典微信小程序+35套微信小程序源碼+微信小程序合集源碼下載(免費)

          ?干貨~~~2021最新前端學(xué)習(xí)視頻~~速度領(lǐng)取

          ?前端書籍-前端290本高清pdf電子書打包下載


          點贊和在看就是最大的支持??



          瀏覽 77
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产自偷自拍 | 日韩欧美中文字幕在线观看 | 黄片网在线 | 亚洲综合婷婷深深 | 大香蕉伊人5 |