koa 원본 부분 해석 (3)koa-body
5624 단어 원본 코드 해독
관례, 먼저 간단한 사용을 살펴보자
const Koa = require('koa');
const body = require('koa-body');
const app = new Koa();
// parsedMethods koa-body
app.use(body({parsedMethods: ['POST', 'PUT', 'PATCH', 'GET', 'HEAD', 'DELETE']}));
app.use(async function(ctx) {
ctx.body = '123123';
});
app.listen(3001);
a-body 자신의 코드는 사실 몇 줄이 없다. 먼저 한 무더기의 매개 변수(대부분은co-body와formidable에 전달되는 것)를 처리한 다음에 type-is라는 패키지(ctx.is 함수)로 요청한 데이터 유형을 판단한 다음에 서로 다른 유형에 따라co-body와formidable로 해석하고 해석 결과를 얻어 바디나 files에 넣고 나란히 한다.
type-is
그래서 type-is가 어떤 신기한 가방인지 살펴보자. 복잡하게 썼고 Mime-types와 미디어-typer를 끌어들였지만 최종적으로 작용하는 것은 Mime-db라는 가방이다. 이름을 보면 사실 많은 파일 유형이 저장되어 있음을 알 수 있다. 어쨌든 type-is는 요청 유형이 무엇인지(content-type을 통해 판단하는 것이지 요청 내용이 아니다) 일치하도록 koa-body 코드를 붙이면 우리도ctx를 사용할 수 있다.is에서 요청의 유형을 판단하려면 아래의 문법을 베끼면 됩니다
const jsonTypes = [
'application/json',
'application/json-patch+json',
'application/vnd.api+json',
'application/csp-report'
];
//
if (opts.json && ctx.is(jsonTypes)) {
bodyPromise = buddy.json(ctx, {
encoding: opts.encoding,
limit: opts.jsonLimit,
strict: opts.jsonStrict,
returnRawBody: opts.includeUnparsed
});
} else if (opts.urlencoded && ctx.is('urlencoded')) {
// application/x-www-form-urlencoded
bodyPromise = buddy.form(ctx, {
encoding: opts.encoding,
limit: opts.formLimit,
queryString: opts.queryString,
returnRawBody: opts.includeUnparsed
});
} else if (opts.text && ctx.is('text')) {
bodyPromise = buddy.text(ctx, {
encoding: opts.encoding,
limit: opts.textLimit,
returnRawBody: opts.includeUnparsed
});
} else if (opts.multipart && ctx.is('multipart')) {
// formidable
bodyPromise = formy(ctx, opts.formidable);
}
//
bodyPromise = bodyPromise || Promise.resolve({});
type-is에 hasbody라는 함수가 있는데 get 요청은 이 함수의 판단에 따라 바디가 없다고 여겨지기 때문에 get 요청이 얻은 결과는 모두 빈 대상이다. 이 빈 대상은 위 코드 세그먼트의 마지막 문장인 Promise에서 나온다.resolve({}).
function hasbody (req) {
return req.headers['transfer-encoding'] !== undefined ||
!isNaN(req.headers['content-length'])
}
function typeofrequest (req, types_) {
var types = types_
// no body
if (!hasbody(req)) {
return null
}
//
}
is 함수의 사용 방법과 출력 결과에 대해koa 본체의 코드 주석에도 비교적 상세한 소개가 있는데 리퀘스트에 있습니다.
co-body
다음에 우리는 코바디를 살펴보자. 코드 구조가 매우 간단하고 json,form,text라는 세 가지 형식의 해석을 제공했다. 주로 inflation과raw-body에 의존한다. 먼저 text를 붙인다. 가장 간단하다. json과form도 차이가 많지 않고 매개 변수(주로 encoding과limit 매개 변수)를 처리했다. inflation과raw-body로 해석하고 되돌아왔다. 코바디와 똑같다.
module.exports = function(req, opts){
req = req.req || req;
opts = utils.clone(opts);
// defaults
var len = req.headers['content-length'];
var encoding = req.headers['content-encoding'] || 'identity';
if (len && encoding === 'identity') opts.length = ~~len;
opts.encoding = opts.encoding === undefined ? 'utf8': opts.encoding;
opts.limit = opts.limit || '1mb';
// raw-body returns a Promise when no callback is specified
return Promise.resolve()
.then(function() {
//
return raw(inflate(req), opts);
})
.then(str => {
// ensure return the same format with json / form
return opts.returnRawBody ? { parsed: str, raw: str } : str;
});
};
그래서 우리는 inflation과raw-body가 어떻게 된 일인지 다시 보았다. inflation은 비교적 간단하고 콘텐츠-encoding의 유형에 따라 서로 다른 조작을 한다. 만약에 gzip과 deflate라면 zlib을 호출한다.Unzip에서 압축을 풀고 identity라면 입력 값을 되돌려줍니다.
raw-body에 대해서 말하자면, 그가 하는 일은stream 해석이고, stream에 대한 세부 사항은 이 편을 보십시오.https://blog.csdn.net/u011393161/article/details/104472698그리고 무서운 가방도 보여요. iconv-lite, 관심 있으면 볼 수 있어요.
formidable
만약에 우리의 데이터 유형이 type-is에 의해 multipart로 판단된다면formidable를 호출하여 해석할 것이다.formidable 자체도 여러 가지 형식의 해석을 제공했는데 json,multipart,urlencoded 등이 있기 때문에 실제로co-body와formidable는 약간 중첩되어 감각적으로formidable가 있으면 충분하다.
구조상formidable도 각종 포맷의 각각의 해석 실현을 제공했다. 주로 write와end 두 함수이다. 멀티파트 포맷의 해석은 비교적 복잡하게 쓰여졌기 때문에 우리는 json 포맷이나urlencoded 포맷의 해석을 먼저 볼 수 있다. 그러나koa-body의 코드를 약간 수정해야 한다. 그렇지 않으면 이 두 포맷은co-body로 해석되어formidable에 들어가지 않는다. 여기에는 수정된 코드를 붙이지 않고 매우 간단하다.
우리 먼저 json의 해석을 살펴보자.formidable는 아래의 정규를 통해 콘텐츠-type에 대한 판단을 통해 해석 형식을 결정하는데,koa-body의 판단 방법과 일치하지 않아 어색하다
this.headers['content-type'].match(/json/i)
this.headers['content-type'].match(/urlencoded/i)
this.headers['content-type'].match(/multipart/i)
this.headers['content-type'].match(/octet-stream/i) // 。。。
formidable의parse 함수의 주요 절차는 writeHeaders 함수에서 호출하는 것입니다ArseContent Type, 대응하는 형식의 해석기를 초기화한 다음stream의 이벤트를 등록하기 시작합니다. 데이터 이벤트가 등록되면stream이 유동 모드에 들어가면 해석기의 write 함수가 실행됩니다. 해석 과정에서 사용자 정의 이벤트가 있습니다. 구독 처리를 할 수 있습니다.koa-body에서 error,field,file 등 이벤트를 구독했고 사실 리셋 함수를 통해 해석된fields와 files를 얻을 수 있습니다.
json 포맷의 해석은 비교적 간단하다.chunks에 데이터를 계속 쓰면 된다.multipart는 비교적 복잡하다.multipart를 구성하는 데이터는 모두 매우 번거롭다.나도 처음으로 multipart의 콘텐츠-type이 사실 이와 같다는 것을 알아차렸다.
multipart/form-data; boundary=--------------------------010958153996667037724890
form-data 이 패키지는node단에서FormData의 데이터를 시뮬레이션할 수 있습니다.multipartparser는 전송된 데이터 형식에 따라 하나하나 분리하여 분석하여multipart 를 볼 수 있습니다parser 안에 큰 switch가 있는데 그 안에 각 부분을 표시하여 구체적인 세부 사항을 전개하지 않습니다
결어
비교적 세부적인 실현을 말하지 못한 것 같아서 정말 부끄럽다. 그러나 첫째, 자신이 이치에 맞지 않고 잘 알고 있다. 둘째, 많은 처리가 흐름과 버퍼이다. 일반적인 데이터처럼 쉽게 볼 수 없고 시간이 나면 나중에 다시 보충한다.