常见的请求数据类型:
-
application/json 常见于post请求 未经过任何处理 以json的格式通过body传输
-
application/x-www-form-urlencoded 提交的表单数据会转换为键值对并按照key1=val&key2=val2的方式进行编码,常见于POST提交表单以及原生的处理方式。
-
multipart/form-data 多媒体类型 多用于上传图片文件等 以boundary作为分隔。
-
text/xml 以xml的格式传输数据 多用于文本传输
Koa-body 原理解析:
- 核心主要依赖于co-body 做上述4种不同的数据格式的转换。
- 通过patchNodeAndKoa 进行不同数据格式的判断。最终返回响应体。
1 import { KoaBodyMiddlewareOptionsSchema } from './types'; 2 import type { KoaBodyMiddlewareOptions } from './types'; 3 import type { Context, Middleware, Next } from 'koa'; 4 import * as Koa from 'koa'; 5 import type { Files } from 'formidable'; 6 import coBody from 'co-body'; 7 import toHttpMethod from './utils/string-method-to-enum-method'; 8 import throwableToError from './utils/throwable-to-error'; 9 import { isJsonBody, isMultipartBody, isTextBody, isUrlencodedBody } from './utils/body-type-util'; 10 import parseWithFormidable from './utils/parse-with-formidable'; 11 import { patchNodeAndKoa } from './utils/patch-util'; 12 import type { ContextWithBodyAndFiles } from './utils/patch-util'; 13 14 export * from './types'; 15 16 declare module 'koa' { 17 interface Request extends Koa.BaseRequest { 18 body?: any; 19 files?: Files; 20 } 21 } 22 23 export function koaBody(options: Partial<KoaBodyMiddlewareOptions> = {}): Middleware { 24 const validatedOptions = KoaBodyMiddlewareOptionsSchema.parse(options); 25 const optionsToUse = { ...options, ...validatedOptions }; 26 return async (ctx: Context, next: Next) => { 27 const isJson = isJsonBody(ctx, optionsToUse); 28 const isText = isTextBody(ctx, optionsToUse); 29 const isUrlencoded = isUrlencodedBody(ctx, optionsToUse); 30 const isMultipart = isMultipartBody(ctx, optionsToUse); 31 const { 32 encoding, 33 jsonStrict, 34 jsonLimit, 35 includeUnparsed: returnRawBody, 36 formLimit, 37 textLimit, 38 queryString, 39 formidable, 40 one rror, 41 patchNode, 42 patchKoa, 43 } = optionsToUse; 44 // only parse the body on specifically chosen methods 只解析body中指定的请求方法 45 if (validatedOptions.parsedMethods.includes(toHttpMethod(ctx.method.toUpperCase()))) { 46 try { 47 if (isJson) { // application/json 数据格式 48 const jsonBody = await coBody.json(ctx, { 49 encoding, 50 limit: jsonLimit, 51 strict: jsonStrict, 52 returnRawBody, 53 }); 54 patchNodeAndKoa(ctx as ContextWithBodyAndFiles, jsonBody, { 55 isText, 56 includeUnparsed: returnRawBody, 57 isMultipart, 58 patchKoa, 59 patchNode, 60 }); 61 } else if (isUrlencoded) { // urlencode数据格式 key=value value默认编码 get和post请求都可使用 62 const urlEncodedBody = await coBody.form(ctx, { 63 encoding, 64 limit: formLimit, 65 queryString: queryString, 66 returnRawBody, 67 }); 68 patchNodeAndKoa(ctx as ContextWithBodyAndFiles, urlEncodedBody, { 69 isText, 70 includeUnparsed: returnRawBody, 71 isMultipart, 72 patchKoa, 73 patchNode, 74 }); 75 } else if (isText) { // 文本数据格式 76 const textBody = await coBody.text(ctx, { 77 encoding, 78 limit: textLimit, 79 returnRawBody, 80 }); 81 patchNodeAndKoa(ctx as ContextWithBodyAndFiles, textBody, { 82 isText, 83 includeUnparsed: returnRawBody, 84 isMultipart, 85 patchKoa, 86 patchNode, 87 }); 88 } else if (isMultipart) { // 多媒体数据格式 89 const multipartBody = await parseWithFormidable(ctx, formidable || {}); 90 patchNodeAndKoa(ctx as ContextWithBodyAndFiles, multipartBody, { 91 isText, 92 includeUnparsed: returnRawBody, 93 isMultipart, 94 patchKoa, 95 patchNode, 96 }); 97 } 98 } catch (parsingError) { 99 const error = throwableToError(parsingError); 100 if (typeof one rror === 'function') { 101 one rror(error, ctx); 102 } else { 103 throw error; 104 } 105 } 106 } else { // 处理未指定的请求方法 107 patchNodeAndKoa( 108 ctx as ContextWithBodyAndFiles, 109 {}, 110 { 111 isText, 112 includeUnparsed: returnRawBody, 113 isMultipart, 114 patchKoa, 115 patchNode, 116 }, 117 ); 118 } 119 120 return next(); 121 }; 122 } 123 124 export default koaBody;
1 export function patchNodeAndKoa(ctx: ContextWithBodyAndFiles, body: any, options: PatchOptions) { 2 const { patchKoa, patchNode, isMultipart, includeUnparsed, isText } = options; 3 // 请求放置在Node 4 if (patchNode) { 5 if (isMultipart) { 6 ctx.req.body = body.fields; 7 ctx.req.files = body.files; 8 } else if (includeUnparsed) { 9 ctx.req.body = body.parsed || {}; 10 if (!isText) { 11 ctx.req.body[symbolUnparsed] = body.raw; 12 } 13 } else { 14 ctx.req.body = body; 15 } 16 } 17 if (patchKoa) { // 请求放置在Koa 18 if (isMultipart) { 19 ctx.request.body = body.fields; 20 ctx.request.files = body.files; 21 } else if (includeUnparsed) { 22 ctx.request.body = body.parsed || {}; 23 if (!isText) { 24 ctx.request.body[symbolUnparsed] = body.raw; 25 } 26 } else { 27 ctx.request.body = body; 28 } 29 } 30 }
标签:body,isText,const,koa,ctx,中间件,isMultipart,import From: https://www.cnblogs.com/taue997/p/17403134.html