Open onvno opened 4 years ago
index.js
return buildProxyReq(container) .then(resolveProxyHost) .then(decorateProxyReqOpts) .then(resolveProxyReqPath) .then(decorateProxyReqBody) .then(prepareProxyReq) .then(sendProxyRequest) .then(copyProxyResHeadersToUserRes) .then(decorateUserRes) .then(sendUserRes) .then(next);
scopeContainer
return { user: { ctx: ctx, }, proxy: { req: {}, res: {}, resData: undefined, // from proxy res bodyContent: undefined, // for proxy req reqBuilder: {}, // reqOpt, intended as first arg to http(s)?.request }, options: resolveOptions(userOptions), params: { host: host, userOptions: userOptions } };
resolveOptions
return { proxyReqPathResolver: options.proxyReqPathResolver, proxyReqOptDecorator: options.proxyReqOptDecorator, proxyReqBodyDecorator: options.proxyReqBodyDecorator, userResDecorator: options.userResDecorator, filter: options.filter || defaultFilter, // For backwards compatability, we default to legacy behavior for newly added settings. parseReqBody: isUnset(options.parseReqBody) ? true : options.parseReqBody, reqBodyEncoding: resolveBodyEncoding(options.reqBodyEncoding), headers: options.headers, preserveReqSession: options.preserveReqSession, https: options.https, port: options.port, reqAsBuffer: options.reqAsBuffer, timeout: options.timeout, limit: options.limit, };
buildProxyReq
responseArray[1]对应createReqOptions
responseArray[1]
createReqOptions
var parseBody = (!options.parseReqBody) ? Promise.resolve(null) : requestOptions.bodyContent(ctx, options); var createReqOptions = requestOptions.create(ctx, options, host); Container.proxy.bodyContent = responseArray[0]; Container.proxy.reqBuilder = responseArray[1];
requestOptions
createRequestOptions对应上边create
createRequestOptions
create
function reqHeaders(ctx, options) { var headers = options.headers || {}; var skipHdrs = [ 'connection', 'content-length' ]; if (!options.preserveHostHdr) { skipHdrs.push('host'); } var hds = extend(headers, ctx.headers, skipHdrs); hds.connection = 'close'; return hds; } function createRequestOptions(ctx, options) { // prepare proxyRequest var reqOpt = { headers: reqHeaders(ctx, options), method: ctx.method, path: ctx.path, // params: req.params, }; if (options.preserveReqSession) { reqOpt.session = ctx.session; } return Promise.resolve(reqOpt); }
resolveProxyHost
container.proxy.reqBuilder.host = parsedHost.host; container.proxy.reqBuilder.port = container.options.port || parsedHost.port; container.proxy.requestModule = parsedHost.module;
decorateProxyReqOpts
处理参数中的proxyReqOptDecorator,用于更新reqBuilder
proxyReqOptDecorator
reqBuilder
var resolverFn = container.options.proxyReqOptDecorator || defaultDecorator; return Promise .resolve(resolverFn(container.proxy.reqBuilder, container.user.ctx)) .then(function(processedReqOpts) { delete processedReqOpts.params; container.proxy.reqBuilder = processedReqOpts; return Promise.resolve(container); });
resolveProxyReqPath
处理参数中的proxyReqPathResolver,用于更新reqBuilder.path
proxyReqPathResolver
reqBuilder.path
var resolverFn = container.options.proxyReqPathResolver || defaultProxyReqPathResolver; return Promise .resolve(resolverFn(container.user.ctx)) .then(function(resolvedPath) { container.proxy.reqBuilder.path = resolvedPath; return Promise.resolve(container); });
decorateProxyReqBody
用于更新container.proxy.bodyContent
container.proxy.bodyContent
var resolverFn = container.options.proxyReqBodyDecorator || defaultDecorator; return Promise .resolve(resolverFn(container.proxy.bodyContent, container.user.ctx)) .then(function(bodyContent) { container.proxy.bodyContent = bodyContent; return Promise.resolve(container); });
prepareProxyReq
用于更新header:content-length,accept-charset
content-length
accept-charset
function prepareProxyReq(container) { return new Promise(function(resolve) { var bodyContent = container.proxy.bodyContent; var reqOpt = container.proxy.reqBuilder; if (bodyContent) { bodyContent = container.options.reqAsBuffer ? as.buffer(bodyContent, container.options) : as.bufferOrString(bodyContent); reqOpt.headers['content-length'] = getContentLength(bodyContent); if (container.options.reqBodyEncoding) { reqOpt.headers['accept-charset'] = container.options.reqBodyEncoding; } } container.proxy.bodyContent = bodyContent; resolve(container); }); }
sendProxyRequest
执行请求,此处使用了原生的http和https模块,注意到当请求结束后会拿到整合的信息,然后走到下一步,所以此处可能可以优化直接转发,无需整合还要继续执行下一步,参见自己总结的stream流2
http
https
这篇需要单独写
copyProxyResHeadersToUserRes
将请求返回的头信息,set到实际请求的header中:
function copyProxyResHeadersToUserRes(container) { return new Promise(function(resolve) { var ctx = container.user.ctx; var rsp = container.proxy.res; if (!ctx.headerSent && ctx.status !== 504) { ctx.status = rsp.statusCode; Object.keys(rsp.headers) .filter(function(item) { return item !== 'transfer-encoding'; }) .forEach(function(item) { ctx.set(item, rsp.headers[item]); }); } resolve(container); }); }
decorateUserRes
处理返回头,并对返回内容进行压缩
sendUserRes
返回内容
源码仓库:koa-better-http-proxy
index.js
scopeContainer
resolveOptions
buildProxyReq
responseArray[1]
对应createReqOptions
requestOptions
createRequestOptions
对应上边create
resolveProxyHost
decorateProxyReqOpts
处理参数中的
proxyReqOptDecorator
,用于更新reqBuilder
resolveProxyReqPath
处理参数中的
proxyReqPathResolver
,用于更新reqBuilder.path
decorateProxyReqBody
用于更新
container.proxy.bodyContent
prepareProxyReq
用于更新header:
content-length
,accept-charset
sendProxyRequest
执行请求,此处使用了原生的
http
和https
模块,注意到当请求结束后会拿到整合的信息,然后走到下一步,所以此处可能可以优化直接转发,无需整合还要继续执行下一步,参见自己总结的stream流2copyProxyResHeadersToUserRes
将请求返回的头信息,set到实际请求的header中:
decorateUserRes
处理返回头,并对返回内容进行压缩
sendUserRes
返回内容