关于koa:koakoabodyparser源码

/**! * koa-body-parser - index.js * Copyright(c) 2014 * MIT Licensed * * Authors: * dead_horse <dead_horse@qq.com> (http://deadhorse.me) * fengmk2 <m@fengmk2.com> (http://fengmk2.com) */'use strict';/** * Module dependencies. */var parse = require('co-body');var copy = require('copy-to');/** * @param [Object] opts * - {String} jsonLimit default '1mb' * - {String} formLimit default '56kb' * - {string} encoding default 'utf-8' * - {Object} extendTypes */module.exports = function (opts) { opts = opts || {}; var detectJSON = opts.detectJSON; var onerror = opts.onerror; var enableTypes = opts.enableTypes || ['json', 'form']; var enableForm = checkEnable(enableTypes, 'form'); var enableJson = checkEnable(enableTypes, 'json'); var enableText = checkEnable(enableTypes, 'text'); var enableXml = checkEnable(enableTypes, 'xml'); opts.detectJSON = undefined; opts.onerror = undefined; // force co-body return raw body opts.returnRawBody = true; // default json types var jsonTypes = [ 'application/json', 'application/json-patch+json', 'application/vnd.api+json', 'application/csp-report', ]; // default form types var formTypes = [ 'application/x-www-form-urlencoded', ]; // default text types var textTypes = [ 'text/plain', ]; // default xml types var xmlTypes = [ 'text/xml', 'application/xml', ]; var jsonOpts = formatOptions(opts, 'json'); var formOpts = formatOptions(opts, 'form'); var textOpts = formatOptions(opts, 'text'); var xmlOpts = formatOptions(opts, 'xml'); var extendTypes = opts.extendTypes || {}; extendType(jsonTypes, extendTypes.json); extendType(formTypes, extendTypes.form); extendType(textTypes, extendTypes.text); extendType(xmlTypes, extendTypes.xml); return async function bodyParser(ctx, next) { // 判断ctx.request.body是否曾经被设置过,如果是则间接通过 if (ctx.request.body !== undefined) return await next(); // disableBodyParser 为True,间接通过不解析,见API if (ctx.disableBodyParser) return await next(); try { // 解析body的入口 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(); }; // 别离对json、from、text、xml四种格局进行解析,其余的间接返回{} async function parseBody(ctx) { // enableJson 是否开启JSON解析, option 参数配置 // detectJSON 自定义检测是否为JSON申请 option 参数配置 // Content-Type是否为JSON相干 if (enableJson && ((detectJSON && detectJSON(ctx)) || ctx.request.is(jsonTypes))) { // 最终还是应用co-body去解析 return await parse.json(ctx, jsonOpts); } if (enableForm && ctx.request.is(formTypes)) { return await parse.form(ctx, formOpts); } if (enableText && ctx.request.is(textTypes)) { return await parse.text(ctx, textOpts) || ''; } if (enableXml && ctx.request.is(xmlTypes)) { return await parse.text(ctx, xmlOpts) || ''; } return {}; }};function formatOptions(opts, type) { var res = {}; copy(opts).to(res); res.limit = opts[type + 'Limit']; return res;}function extendType(original, extend) { if (extend) { if (!Array.isArray(extend)) { extend = [extend]; } extend.forEach(function (extend) { original.push(extend); }); }}function checkEnable(types, type) { return types.includes(type);}由下面的代码能够看出,koa-bodyparser最终还是通过co-body去解析申请内容并生成ctx.req.body.上面以parse.json为例,探索下大略过程: ...

June 28, 2022 · 3 min · jiezi

关于koa:koa异常处理详解

文章不易,请关注公众号 毛毛虫的小小蜡笔,多多反对,谢谢 问题koa是怎么解决异样的? 剖析首先理解下node.js是怎么解决异样的 一般来说,node.js顶层有个uncaughtException事件,当异样没被捕捉的时候,就会一层层回升,直到触发定义好的uncaughtException事件。 但有个问题,node.js最大的特点是异步机制。比方读取文件信息的stat的异步写法: require('fs').stat('test.txt', function(err, res) { if (err) { throw err; }})如果读取文件信息过程中出错了,比方文件不存在。那就会执行throw err。 就算用了try catch,也不能捕捉异步函数。 详情 请查看:毛毛虫的小小蜡笔

June 24, 2022 · 1 min · jiezi

关于koa:koa原理详解

文章不易,请关注公众号 毛毛虫的小小蜡笔,多多反对,谢谢 先看个Demoapp.use(async (ctx, next) => { console.log(1) await next() console.log(2) ctx.body = 'Hello Koa';});app.use(async (ctx, next) => { console.log(3) await next() console.log(4)});app.use(async (ctx, next) => { console.log(5)});输入后果是:13542 这就是所谓的洋葱模型。第一个中间件在最外层,而后第二个在第二层,第三个则是最外面一层。所以先执行1,而后到第二层的3,再到最外面的5,执行完后再到第二层的4,最初返回到第一层的2。 看源码app.use最次要的是把中间件存起来:this.middleware.push(fn)。 详情 请查看:毛毛虫的小小蜡笔

May 31, 2022 · 1 min · jiezi

关于koa:koa源码

源码目录构造Applicationapplication.js次要是对 App 做的一些操作,包含创立服务、在 ctx 对象上挂载 request、response 对象,以及解决异样等操作。接下来将对这些实现进行具体论述。 Koa 创立服务的原理Node 原生创立服务const http = require("http");const server = http.createServer((req, res) => { res.writeHead(200); res.end("hello world");});server.listen(4000, () => { console.log("server start at 4000");});module.exports = class Application extends Emitter { /** * Shorthand for: * * http.createServer(app.callback()).listen(...) * * @param {Mixed} ... * @return {Server} * @api public */ listen(...args) { debug("listen"); const server = http.createServer(this.callback()); return server.listen(...args); } /** * Return a request handler callback * for node's native http server. * * @return {Function} * @api public */ callback () { const fn = compose(this.middleware) if (!this.listenerCount('error')) this.on('error', this.onerror) const handleRequest = (req, res) => { const ctx = this.createContext(req, res) return this.handleRequest(ctx, fn) } return handleRequest } /** * Handle request in callback. * * @api private */ handleRequest (ctx, fnMiddleware) { const res = ctx.res res.statusCode = 404 const onerror = err => ctx.onerror(err) const handleResponse = () => respond(ctx) onFinished(res, onerror) return fnMiddleware(ctx).then(handleResponse).catch(onerror) }};中间件实现原理中间件应用例子 ...

May 4, 2022 · 4 min · jiezi

关于koa:koa搭建nodejs项目并注册接口

应用nodejs注册接口逻辑解决会比较复杂,间接通过express或者koa可能简化开发流程,这里记录用koa来搭建nodejs我的项目并注册接口,对koa不太熟悉的话能够参考这一篇。让nodejs开启服务更简略--koa篇 我的项目构造我的项目整体构造如下,将不同性能的文件按模块划分,使得代码逻辑更为清晰 node_modules // 装置的包src // 本人编码的局部 app // 注册的app constants // 定义常量 controller // 注册接口所应用到的办法 middleware // 解决数据的中间件 router // 路由 service // 定义sql语句 utils // 解决数据的办法 main.js // 入口.env // 放到环境变量的配置文件 package-lock.json // 包的依赖关系package.json // 须要装置哪些包注册appkoa中所有的操作都须要通过注册的这个app对象来实现,先在 app/index.js 中注册并导出 const Koa = require('koa')const app = new Koa() module.exports = apphttp开启服务我的项目根目录建设 main.js文件,引入app对象,开启http服务 const app = require('./app')const { APP_PORT } = require('./app/config')app.listen(APP_PORT, ()=>{ console.log('开启服务啦')})账号密码、端口号等信息间接写在文件中是不平安的,上传或共享我的项目的时候容易泄露,所以保留到不影响我的项目的的文件当中,根目录中新增 .env 文件,应用 dotenv 将 .env 文件中的配置项注册到环境变量中 APP_PORT=8000app文件夹中新增config.js文件用于保留配置信息,避免随便更改 const dotenv = require('dotenv')dotenv.config();module.exports = { APP_PORT} = process.env启动 main.js就曾经能够监听8000端口了,因为没有对申请做出响应,所以此时拜访8000,只能返回 Not Find ...

September 19, 2021 · 1 min · jiezi

关于koa:koa项目热更新和es6语法兼容

热更新很简略,须要应用到nodemon。 用法如下: npm i nodemon -D// package.json"scripts": { "start": "nodemon src/index.js" },而后运行npm run start es语法反对这里须要用到如下插件: webpack & webpack-cliclean-webpack-plugin: 革除dist目录webpack-node-externals: 不对node_modules进行解决@babel/core: es6反对@babel/node: 调试应用@babel/preset-env: 新语法的反对babel-loadercross-env: 环境变量的解决 webpack.config.js 配置如下: const path = require('path');var nodeExternals = require('webpack-node-externals');const { CleanWebpackPlugin } = require('clean-webpack-plugin');const webpackconfig = { target: 'node', mode: 'development', entry: { server: path.join(__dirname, 'src/index.js') }, devtool: 'eval-source-map', output: { filename: '[name].bundle.js', path: path.join(__dirname, './dist') }, module: { rules: [ { test: /\/(js|jsx)$/, use: { loader: 'babel-loader' }, exclude: [path.join(__dirname, '/node_modules')] } ], }, externals: [nodeExternals()], plugins: [ new CleanWebpackPlugin() ], node: { console: true, global: true, process: true, Buffer: true, __filename: true, __dirname: true, setImmediate: true, path: true } }module.exports = webpackconfig.babelrc 配置如下: ...

April 23, 2021 · 1 min · jiezi

关于koa:Koa初探一

koa初探(一)当咱们在学习某个新的知识点的时候,大部分状况下都是关上百度,或者谷歌,而后在搜寻框中输出某个名词,这个时候大抵在搜寻项的后面几个,咱们就能够看到一个对于这个货色的官网文档,而后点进去,根本就是对于这个货色的所有api和应用办法啦~ 当然,一开始的时候我兴许会饶有兴致地依据官网给出的例子在本人的电脑上跑一跑,看一看。很快,当我把例子跑完,我仿佛明确了这到底是怎么一回事的时候,我想要持续摸索,于是就看到了无穷无尽的api,看了两眼,困意????袭来~~~ 讲了一堆废话,该进入正题啦~ 官网给了这样一个例子:大抵解读一下,就是new进去一个koa对象,利用它来创立一个服务器,并且应用了3000端口来监听状态。两头对于申请的解决就是有一堆所谓middleware(中间件)来解决,假如咱们的koa服务器就是一个盒子,丢一个申请(request)进入盒子,而后就能够从盒子中失去一个通过了一系列解决的响应后果(response)。 const Koa = require('koa');const app = new Koa();// loggerapp.use(async (ctx, next) => { await next(); const rt = ctx.response.get('X-Response-Time'); console.log(`${ctx.method} ${ctx.url} - ${rt}`);});// x-response-timeapp.use(async (ctx, next) => { const start = Date.now(); await next(); const ms = Date.now() - start; ctx.set('X-Response-Time', `${ms}ms`);});// responseapp.use(async ctx => { ctx.body = 'Hello World';});app.listen(3000);以上这段代码的调用程序对于只看官网的文字描述还是有点不够清晰的。这看起来就像咱们在写作业的时候,忽然脑海中呈现了奇思妙想,于是在某个工夫点就跑出去游玩了,玩到兴致快没有的时候,还记得作业没有写完,而后就又跑回去,从方才停留的作业的中央又持续往下写,当然在玩的过程中还会有其余更好玩的,于是不停地跑出去,不过这个贪玩的小孩至多还记得以后玩完了还会跑回去把上一次没有玩完的事件做完。

January 17, 2021 · 1 min · jiezi

关于koa:Koa入门教程6初探源码

本文纲要express与koa的比照Koa1 内核源码简要介绍 Koa2 内核与 koa1 的区别理解 Koa 中 http 协商缓存的实现机制koa-router 源码koa-view 源码express本文咱们不解说express的源码。然而express的实现机制对于咱们理解 TJ 在设计框架时的思路有肯定的参考意义。express 实现了一个相似于流的申请处理过程,其源码比 Koa 还要略微简单一点(次要是其内置了Router概念来实现路由)。如果对 express 的源码感兴趣的能够参考这两篇文章: 从express源码中探析其路由机制 NodeJS框架之Express4.x源码剖析 exporess和koa都是用来对http申请进行 接管、解决、响应。在这个过程中,express和koa都有提供中间件的能力来对申请和响应进行串联。同时要提供一个封装好的 执行上下文 来串联中间件。 因而,koa和express就是把这些http解决能力打包在一起的一个残缺的后端利用框架。波及到了一个申请解决的残缺流程,其中蕴含了这些常识概念:Application、Request、Response、COntext、Session、Cookie。 express跟koa的区别是,express应用的ES5时代的语言能力(没有应用generator和async),因而express实现的中间件机制是传统的串行的流式运行(从第一个运行到最初一个后输入响应);而koa应用了generator或async从而实现了一种洋葱模型的中间件机制,所谓洋葱模型实际上就是中间件函数在运行过程中能够停下来,把执行权交给前面的中间件,等到适合的机会再回到函数内持续往下执行 Koa1 内核本文咱们还是次要剖析 Koa1 的代码(因为 Generator 比 async 要绕一些难一些),我看的代码是基于 Koa 1.6.0。 对于 Koa1 来说,其实现是基于 ES6 的 Generator 函数。Generator 给了咱们用同步代码编写异步的可能,他能够让程序执行流 流向 下方,在异步完结之后再返回之前的中央执行。Generator 就像一个迭代器,能够通过它的 next 办法一直去迭代来实现函数的步进式执行。对于 Generator 函数解决异步问题的学习能够参考 阮一峰的 ES6 教程 Generator函数与异步 Koa 内核只有 1千 行左右的代码。共蕴含 4 个文件: application.jsrequest.jsresponse.jscontext.js咱们从 package.json 中能够看到 Koa 的主入口是 lib/application.js. 这个入口做的事件便是导出了一个 Application 的class类。(能够看到 Koa 的实现相比express曾经比拟面向对象了) ...

November 13, 2020 · 5 min · jiezi

关于koa:Koa入门教程5升级为Koa2

先来翻译一波 官网的 migration指南: 从 Koa v1.x 迁徙到 v2.x新的中间件函数签名Koa v2 引入了一个新的中间件签名 老的中间件签名形式 (v1.x) 将在v3版本删除 新的 middleware 签名如下: // 用async箭头函数app.use(async (ctx, next) => { try { await next() // next不再是generator迭代器,而是一个asycn函数了 } catch (err) { ctx.body = { message: err.message } ctx.status = err.status || 500 }})app.use(async ctx => { const user = await User.getById(this.session.userid) // 用await代替yield ctx.body = user //用ctx变量代替this})你不是只能用async函数-你只须要保障传递一个返回promise的函数一个一般返回promise的函数照样能够工作。 这个中间件函数签名改成了传入一个严格的ctx参数 ( Context 对象),而不是用this来拜访以后申请上下文. 这个扭转使得 koa 更能兼容es6箭头函数捕捉this. 在v2.x中应用v1.x的中间件Koa v2.x 在调用app.use的时候能够兼容generator的middleware,它应用koa-convert.来干这件事。然而还是倡议你连忙迁徙这些v1的中间件。 ...

November 13, 2020 · 2 min · jiezi

关于koa:Koa入门教程4开发并部署todolist应用

我的项目简介todo-list 利用是一个罕用的练手利用。他次要蕴含以下几个性能: input框增加工作,回车后增加到工作列表点击工作列表条目,或点击条目后的删除按钮,能够删除一个todo我的项目点击 实现 按钮,能够把某个条目标记为已实现这个我的项目咱们采纳前后端齐全拆散的形式来开发 前端技术栈: Vue2.x、Axios、Vue-Router、Vuex 、css3 Flex后端技术栈: Koa1.x 、 koa-body-parser 、 koa-logger 、 koa-json 我的项目目录构造组织在前后端拆散的我的项目中,我倡议采纳前端目录驱动的形式。即优先以前端架构进行组织,在前端目录架构中搁置一个后端目录 用于api服务并同时作为前端编译后果的托管容器进行部署。 起因在于,后端目录个别是用于部署的,而前端利用如果不是独自部署的话 则须要搁置到后端目录中一起托管。 基于前端编译后输入的方便性,把后端目录放在前端目录外面,build时就比拟不便了。 当然,你如果保持本人的目录哲学,也无可非议。 初始化在我的项目根目录下,先应用 vue-cli 工具初始化一个基于 webpack 脚手架的 Vue2.x我的项目。 npm i vue-cli -g# 进入我的项目目录根vue init webpack .npm install此时 前端目录和文件曾经创立结束。前端依赖也曾经装置。基于前端的 package.json 根底之上,咱们再 在我的项目根目录下执行 npm i koa-logger未完待续

November 2, 2020 · 1 min · jiezi

关于koa:Koa入门教程3错误和异常处理

Node.js 中的异样Node.js 跟 JavaScript一样,同步代码中的异样咱们能够通过 try catch 来捕捉. 异步回调异样但异步代码呢? 咱们来看一个 http server 启动的代码,这个也是个典型的异步代码。 const http = require('http')try { const server = http.createServer(function (req, res) { console.log('来了') throw new Error('hi') res.end('helo') }) server.listen(3002)}catch (err) { console.log('出错了')}咱们发现异步代码的异样无奈间接捕捉。这会导致 Node.js 过程退出。最显著的就是 web server 间接挂掉了。 异步代码也有解决办法,咱们间接把try catch 写在异步代码的回调外面: const http = require('http')try { const server = http.createServer(function (req, res) { try { throw new Error('hi') } catch (err) { console.log('出错了') } res.end('helo') }) server.listen(3002)}catch (err) { console.log('出错了')}这样也能catch到谬误。 ...

November 1, 2020 · 2 min · jiezi

关于koa:Koa入门教程2常用中间件

中间件执行流程中间件的执行流程,能够用上面这张图片来活泼的阐明(图片应用了 Koa 2 的 async 语法): 对于 Koa 1 来说也相似,只是 async 函数换作 generator 函数,await 换作 yield 关键字。 对于前端程序员,能够把 yield 之前的代码认为是捕捉阶段,yield 之后的认为的冒泡阶段,从而了解多个中间件之间代码的执行流程。 路由中间件路由个别属于业务代码,咱们个别放在其余根底中间件之后来注册。路由的基本原理就是判断 url path, 而后决定是否执行某个中间件逻辑。 简略实现能够相似这样: const Koa = require('koa')const app = new Koa()app.use(function *(next) { if (this.path === '/home') { this.body = '首页' } else { yield next } console.log('这里会执行哦')})app.use(function *(next) { if (this.path === '/admin') { this.body = '治理端' }})app.listen(3000)能够看到,对于不合乎本中间件的申请 path, 就间接抛弃,并去执行下一个中间件。如果所有中间件都匹配不到,会返回 404(Koa 默认行为). ...

October 30, 2020 · 3 min · jiezi

关于koa:Koa入门教程1开端

前言Koa 是一个粗劣玲珑的基于 Node.js 的 Web 框架。目前有 1.x 和 2.x 2 个大的版本 其中 2.x 版本应用了 Node.js v7.6.0 之后反对的 async await 语法糖,提供了更优雅的异步编程模式。 Koa 有如下特点: 内核精简,不内置中间件. 玲珑但富裕表现力。相似栈的形式运行中间件,Koa 调用上游,而后堆栈开展再将管制再流回上游。简略实用实用async await或generator防止了callback hell优雅的异样捕捉Koa 通过下面的机制防止了以往 connect 等实现的一些问题,例如要实现一个耗时统计时须要将 startTime 层层传递到开端中间件。Koa 与 express 和 connect 的差异如下: 为了一探 Koa 的全貌,咱们基于 Koa 1.x 的版本来开始学习之旅(次要是为了学习generator,其余方面1和2其实原理是一样的)。前面打算的教程如下: 开始。装置和启动罕用中间件错误处理和最佳实际开发并部署一个 todo-list 利用降级为 Koa2初探 Koa 源码装置应用 Koa 搭建一个 Web 利用是极其简略的。Koa 模块裸露了一个 Application 的 class 给 Web 开发者,咱们只需实例化这个 Application,并给它注入适当的 申请和响应解决逻辑. 实际上,整个 Koa 利用的开发模式就是如此简略。 ...

October 11, 2020 · 2 min · jiezi

关于koa:优雅-koa处理异常

一个良好的编码习惯必然离不开异样解决,本文将会介绍如何在koa框架上面如何抛出谬误,并对立解决返回异样。 失常错误处理koa是一个优良的NodeJs web框架,在咱们开发web我的项目的时候,防止不了任何错误处理,包含http谬误以及自定义的业务逻辑解决。在Node.js 中,抛出谬误如下 if(someCondition){ throw Error("Error");}Http错误处理这里应用ctx.throw(400)的形式,抛出http谬误,同时返回一些信息。 ctx.status = 400ctx.body = { msg: "some params is invalid"}此时既返回了状态码,又返回了相干的错误信息。 业务逻辑错误处理如果须要开发Restful API server,这个时候须要定义若干的业务逻辑错误代码,像上面这样的 code码阐明0success-1server error4001token 过期这个时候,就须要在业务层中进行解决。 router.get("/", (ctx, next) => { if(tokenExpire(token)){ const errcode = ERROR_CODE.TOKEN_EXPIRED; ctx.body = { errcode, msg: ERROR_MSG[errcode] } return }})这里,就返回了相干的errcode,通过errcode的形式返回了相干的错误代码 全局捕捉异样解决这里在koa里,全局捕捉异样,这里应用中间件的形式,确保异样能够捕捉到在middlewares建设一个catcherror中间件,达到捕捉到异样的形式 // middlewares/catcherror.jsconst catchError = async(ctx, next) => { try{ await next(); }catch(error){ if(error.errorCode){ console.log("捕捉到异样") return ctx.body = errror.msg; } }}module.exports = catchError这样定义一个中间件,在中间件进行相干的捕捉,确保捕捉到相干的异样,并把这个中间件进行导出。 放在next外面,如果next程序出现异常,就能够实现在中间件进行相干的捕捉。 ...

July 22, 2020 · 1 min · jiezi