国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

深入koa-bodyparser原理解析

2019-11-19 12:17:10
字體:
來源:轉載
供稿:網友

一、前置知識

在理解koa-bodyparser原理之前,首先需要了解部分HTTP相關的知識。

1、報文主體

HTTP報文主要分為請求報文和響應報文,koa-bodyparser主要針對請求報文的處理。

請求報文主要由以下三個部分組成:

  • 報文頭部
  • 空行
  • 報文主體

而koa-bodyparser中的body指的就是請求報文中的報文主體部分。

2、服務器端獲取報文主體流程

HTTP底層采用TCP提供可靠的字節流服務,簡單而言就是報文主體部分會被轉化為二進制數據在網絡中傳輸,所以服務器端首先需要拿到二進制流數據。

談到網絡傳輸,當然會涉及到傳輸速度的優化,而其中一種優化方式就是對內容進行壓縮編碼,常用的壓縮編碼方式有:

  • gzip
  • compress
  • deflate
  • identity(不執行壓縮或不會變化的默認編碼格式)

服務器端會根據報文頭部信息中的Content-Encoding確認采用何種解壓編碼。

接下來就需要將二進制數據轉換為相應的字符,而字符也有不同的字符編碼方式,例如對于中文字符處理差異巨大的UTF-8和GBK,UTF-8編碼漢字通常需要三個字節,而GBK只需要兩個字節。所以還需要在請求報文的頭部信息中設置Content-Type使用的字符編碼信息(默認情況下采用的是UTF-8),這樣服務器端就可以利用相應的字符規則進行解碼,得到正確的字符串。

拿到字符串之后,服務器端又要問了:客戶端,你這一段字符串是啥意思???

根據不同的應用場景,客戶端會對字符串采用不同的編碼方式,常見的編碼方式有:

  • URL編碼方式: a=1&b=2
  • JSON編碼方式: {a:1,b:2}

客戶端會將采用的字符串編碼方式設置在請求報文頭部信息的Content-Type屬性中,這樣服務器端根據相應的字符串編碼規則進行解碼,就能夠明白客戶端所傳遞的信息了。

下面一步步分析koa-bodyparser是如何處理這一系列操作,從而得到報文主體內容。

二、獲取二進制數據流

NodeJS中獲取請求報文主體二進制數據流主要通過監聽request對象的data事件完成:

// 示例一const http = require('http')http.createServer((req, res) => { const body = [] req.on('data', chunk => {  body.push(chunk) })  req.on('end', () => {  const chunks = Buffer.concat(body) // 接收到的二進制數據流  // 利用res.end進行響應處理  res.end(chunks.toString()) })}).listen(1234)

而koa-bodyparser主要是對co-body 的封裝,而【co-body】中主要是采用raw-body 模塊獲取請求報文主體的二進制數據流,【row-body】主要是對上述示例代碼的封裝和健壯性處理。

三、內容解碼

客戶端會將內容編碼的方式放入請求報文頭部信息Content-Encoding屬性中,服務器端接收報文主體的二進制數據了時,會根據該頭部信息進行解壓操作,當然服務器端可以在響應報文頭部信息Accept-Encoding屬性中添加支持的解壓方式。

而【row-body】主要采用 inflation 模塊進行解壓處理。

四、字符解碼

一般而言,UTF-8是互聯網中主流的字符編碼方式,前面也提到了還有GBK編碼方式,相比較UTF-8,它編碼中文只需要2個字節,那么在字符解碼時誤用UTF-8解碼GBK編碼的字符,就會出現中文亂碼的問題。

NodeJS主要通過Buffer處理二進制數據流,但是它并不支持GBK字符編碼方式,需要通過 iconv-lite 模塊進行處理。

【示例一】中的代碼就存在沒有正確處理字符編碼的問題,那么報文主體中的字符采用GBK編碼方式,必然會出現中文亂碼:

const request = require('request')const iconv = require('iconv-lite')request.post({ url: 'http://localhost:1234/', body: iconv.encode('中文', 'gbk'), headers: {  'Content-Type': 'text/plain;charset=GBK' }}, (error, response, body) => { console.log(body) // 發生中文亂碼情況})

NodeJS中的Buffer默認是采用UTF-8字符編碼處理,這里借助【iconv-lite】模塊處理不同的字符編碼方式:

const chunks = Buffer.concat(body)  res.end(iconv.decode(chunks, charset)) // charset通過Content-Type得到

五、字符串解碼

前面已經提到了字符串的二種編碼方式,它們對應的Content-Type分別為:

  • URL編碼 application/x-www-form-urlencoded
  • JSON編碼 application/json

對于前端來說,URL編碼并不陌生,經常會用于URL拼接操作,唯一需要注意的是不要忘記對鍵值對進行decodeURIComponent()處理。

當客戶端發送請求主體時,需要進行編碼操作:

'a=1&b=2&c=3'

服務器端再根據URL編碼規則解碼,得到相應的對象。

// URL編碼方式 簡單的解碼方法實現function decode (qs, sep = '&', eq = '=') { const obj = {} qs = qs.split(sep) for (let i = 0, max = qs.length; i < max; i++) {  const item = qs[i]  const index = item.indexOf(eq)  let key, value  if (~index) {   key = item.substr(0, index)   value = item.substr(index + 1)  } else {   key = item   value = ''  }    key = decodeURIComponent(key)  value = decodeURIComponent(value)  if (!obj.hasOwnProperty(key)) {   obj[key] = value  } } return obj}console.log(decode('a=1&b=2&c=3')) // { a: '1', b: '2', c: '3' }

URL編碼方式適合處理簡單的鍵值對數據,并且很多框架的Ajax中的Content-Type默認值都是它,但是對于復雜的嵌套對象就不太好處理了,這時就需要JSON編碼方式大顯身手了。

客戶端發送請求主體時,只需要采用JSON.stringify進行編碼。服務器端只需要采用JSON.parse進行解碼即可:

const strictJSONReg = /^[/x20/x09/x0a/x0d]*(/[|/{)/;function parse(str) { if (!strict) return str ? JSON.parse(str) : str; // 嚴格模式下,總是返回一個對象 if (!str) return {}; // 是否為合法的JSON字符串 if (!strictJSONReg.test(str)) {  throw new Error('invalid JSON, only supports object and array'); } return JSON.parse(str);}

除了上述兩種字符串編碼方式,koa-bodyparser還支持不采用任何字符串編碼方式的普通字符串。

三種字符串編碼的處理方式由【co-body】模塊提供,koa-bodyparser中通過判斷當前Content-Type類型,調用不同的處理方式,將獲取到的結果掛載在ctx.request.body:

return async function bodyParser(ctx, next) {  if (ctx.request.body !== undefined) return await next();  if (ctx.disableBodyParser) return await next();  try {   // 最重要的一步 將解析的內容掛載到koa的上下文中   const res = await parseBody(ctx);   ctx.request.body = 'parsed' in res ? res.parsed : {};   if (ctx.request.rawBody === undefined) ctx.request.rawBody = res.raw; // 保存原始字符串  } catch (err) {   if (onerror) {    onerror(err, ctx);   } else {    throw err;   }  }  await next(); }; async function parseBody(ctx) {  if (enableJson && ((detectJSON && detectJSON(ctx)) || ctx.request.is(jsonTypes))) {   return await parse.json(ctx, jsonOpts); // application/json等json type  }  if (enableForm && ctx.request.is(formTypes)) {   return await parse.form(ctx, formOpts); // application/x-www-form-urlencoded  }  if (enableText && ctx.request.is(textTypes)) {   return await parse.text(ctx, textOpts) || ''; // text/plain  }  return {}; }};

其實還有一種比較常見的Content-type,當采用表單上傳時,報文主體中會包含多個實體主體:

------WebKitFormBoundaryqsAGMB6Us6F7s3SFContent-Disposition: form-data; name="image"; filename="image.png"Content-Type: image/png------WebKitFormBoundaryqsAGMB6Us6F7s3SFContent-Disposition: form-data; name="text"------WebKitFormBoundaryqsAGMB6Us6F7s3SF--

這種方式處理相對比較復雜,koa-bodyparser中并沒有提供該Content-Type的解析。(下一篇中應該會介紹^_^)

五、總結

以上便是koa-bodyparser的核心實現原理,其中涉及到很多關于HTTP的基礎知識,對于HTTP不太熟悉的同學,可以推薦看一波入門級寶典【圖解HTTP】。

最后留圖一張:

 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 榆林市| 澄城县| 南溪县| 通江县| 无锡市| 彭山县| 泰来县| 岳阳市| 油尖旺区| 宜兰县| 玉田县| 金寨县| 武邑县| 清苑县| 韩城市| 平昌县| 安达市| 舒兰市| 永登县| 株洲市| 准格尔旗| 镇原县| 安徽省| 稻城县| 神池县| 祁连县| 瑞金市| 彝良县| 双牌县| 鸡西市| 高雄县| 虞城县| 富宁县| 瑞昌市| 仙游县| 天门市| 九龙城区| 阿克苏市| 屏南县| 武宣县| 蕉岭县|