1.在hello-koa这个目录下创建一个package.json,这个文件描述了我们的hello-koa工程会用到哪些包。完整的文件内容如下:

{
"name": "hello-koa2",
"version": "1.0.0",
"description": "Hello Koa 2 example with async",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [
"koa",
"async"
],
"author": "Michael Liao",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/michaelliao/learn-javascript.git"
},
"dependencies": {
"koa": "2.0.0"
}
}

其中,dependencies描述了我们的工程依赖的包以及版本号。其他字段均用来描述项目信息,可任意填写。

C:\...\hello-koa> npm install

2.创建koa2工程

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 对于任何请求,app将调用该异步函数处理请求:
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
}); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

还可以直接用命令node app.js在命令行启动程序,或者用npm start启动。npm start命令会让npm执行定义在package.json文件中的start对应命令:

"scripts": {
"start": "node app.js"
}

koa middleware

让我们再仔细看看koa的执行逻辑。核心代码是:

app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
});

每收到一个http请求,koa就会调用通过app.use()注册的async函数,并传入ctxnext参数。

我们可以对ctx操作,并设置返回内容。但是为什么要调用await next()

原因是koa把很多async函数组成一个处理链,每个async函数都可以做一些自己的事情,

然后用await next()来调用下一个async函数。我们把每个async函数称为middleware,这些middleware可以组合起来,完成很多有用的功能。

例如,可以用以下3个middleware组成处理链,依次打印日志,记录处理时间,输出HTML:

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); app.use(async (ctx, next) => {
console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
await next(); // 调用下一个middleware
}); app.use(async (ctx, next) => {
const start = new Date().getTime(); // 当前时间
await next(); // 调用下一个middleware
const ms = new Date().getTime() - start; // 耗费时间
console.log(`Time: ${ms}ms`); // 打印耗费时间
}); app.use(async (ctx, next) => {
console.log('我开始了')
await next(); // 当下面没有use 后将不执行
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
console.log('我结束了')
}); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

middleware的顺序很重要,也就是调用app.use()的顺序决定了middleware的顺序。

此外,如果一个middleware没有调用await next(),会怎么办?答案是后续的middleware将不再执行了。

这种情况也很常见,例如,一个检测用户权限的middleware可以决定是否继续处理请求,还是直接返回403错误:

app.use(async (ctx, next) => {
if (await checkUserPermission(ctx)) {
await next();
} else {
ctx.response.status = 403;
}
});

理解了middleware,我们就已经会用koa了!

最后注意ctx对象有一些简写的方法,例如ctx.url相当于ctx.request.urlctx.type相当于ctx.response.type

处理URL

正常情况下,我们应该对不同的URL调用不同的处理函数,这样才能返回不同的结果。例如像这样写:

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); app.use(async (ctx, next) => {
//ctx.request.path 判断访问路径
if (ctx.request.path === '/') {
ctx.response.body = 'index page';
//如果就有 就执行下一个use
} else {
await next();
}
}); app.use(async (ctx, next) => {
if (ctx.request.path === '/test') {
ctx.response.body = 'TEST page';
} else {
await next();
}
}); app.use(async (ctx, next) => {
if (ctx.request.path === '/error') {
ctx.response.body = 'ERROR page';
} else {
await next();
}
}); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

这么写是可以运行的,但是好像有点蠢。

应该有一个能集中处理URL的middleware,它根据不同的URL调用不同的处理函数,这样,我们才能专心为每个URL编写处理函数。

koa-router

为了处理URL,我们需要引入koa-router这个middleware,让它负责处理URL映射。

先在package.json中添加依赖项:

{
"name": "hello-koa2",
"version": "1.0.0",
"description": "Hello Koa 2 example with async",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [
"koa",
"async"
],
"author": "Michael Liao",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/michaelliao/learn-javascript.git"
},
"dependencies": {
"koa": "2.0.0",
"koa-router": "7.0.0"
}
}

然后用npm install安装。

接下来,我们修改app.js,使用koa-router来处理URL:

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建一个Koa对象表示web app本身:
const app = new Koa(); //log request URL:
app.use(async(ctx,next)=> {
console.log(`Process ${ctx.request.method} ${ctx.request.url}.....`)
await next();
}) //add url-route; 添加访问路径
router.get(`/hello/:name`,async(ctx,next)=> {
var name = ctx.params.name
ctx.response.body = `<h1>Hello,${name}</h1>` }) //add url-route;添加访问路径
router.get('/', async (ctx, next) => {
ctx.response.body = '<h1>Index</h1>';
}); // add router middlware
app.use(router.routes()); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

注意导入koa-router的语句最后的()是函数调用:

const router = require('koa-router')();

相当于:

const fn_router = require('koa-router');
const router = fn_router();

然后,我们使用router.get('/path', async fn)来注册一个GET请求。可以在请求路径中使用带变量的/hello/:name,变量可以通过ctx.params.name访问。

再运行app.js,我们就可以测试不同的URL:

输入首页:http://localhost:3000/

处理post请求

router.get('/path', async fn)处理的是get请求。如果要处理post请求,可以用router.post('/path', async fn)

用post请求处理URL时,我们会遇到一个问题:post请求通常会发送一个表单,或者JSON,它作为request的body发送,但无论是Node.js提供的原始request对象,还是koa提供的request对象,都不提供解析request的body的功能!

所以,我们又需要引入另一个middleware来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中。

koa-bodyparser就是用来干这个活的。

1. 在package.json中添加依赖项:

"koa-bodyparser": "3.2.0"

2.引入koa-bodyparser

const bodyParser = require('koa-bodyparser');

在合适的位置加上:

app.use(bodyParser());

由于middleware的顺序很重要,这个koa-bodyparser必须在router之前被注册到app对象上。

现在我们就可以处理post请求了。写一个简单的登录表单:

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); //log request URL:
app.use(async(ctx,next)=> {
console.log(`Process ${ctx.request.method} ${ctx.request.url}.....`)
await next();
}) //get 请求返回一个body html文本
router.get('/', async (ctx, next) => {
// 响应html文本
ctx.response.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
}); //处理用户提交过来的 post请求
router.post('/signin', async (ctx, next) => {
// 获取用户提交上来的值
var
name = ctx.request.body.name || '',
password = ctx.request.body.password || '';
console.log(`signin with name: ${name}, password: ${password}`); // 对用户提交上来的值进行判断
if (name === 'koa' && password === '12345') {
//如果成功 返回登录成功
ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
} else {
// 如果登录失败 返回登录失败,然后尝试 再次登录
ctx.response.body = `<h1>Login failed!</h1>
<p><a href="/">Try again</a></p>`;
}
}); // add middlware 这个要放前面
app.use(bodyParser()); // add router middlware
app.use(router.routes()); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

注意到我们用var name = ctx.request.body.name || ''拿到表单的name字段,如果该字段不存在,默认值设置为''

类似的,put、delete、head请求也可以由router处理。

重构

现在,我们已经可以处理不同的URL了,但是看看app.js,总觉得还是有点不对劲。

所有的URL处理函数都放到app.js里显得很乱,而且,每加一个URL,就需要修改app.js。随着URL越来越多,app.js就会越来越长。

如果能把URL处理函数集中到某个js文件,或者某几个js文件中就好了,然后让app.js自动导入所有处理URL的函数。这样,代码一分离,逻辑就显得清楚了。最好是这样:

url2-koa/
|
+- .vscode/
| |
| +- launch.json <-- VSCode 配置文件
|
+- controllers/
| |
| +- login.js <-- 处理login相关URL
| |
| +- users.js <-- 处理用户管理相关URL
|
+- app.js <-- 使用koa的js
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包

于是我们把url-koa复制一份,重命名为url2-koa,准备重构这个项目。

我们先在controllers目录下编写index.js

var fn_index = async (ctx, next) => {
ctx.response.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
}; var fn_signin = async (ctx, next) => {
var
name = ctx.request.body.name || '',
password = ctx.request.body.password || '';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'koa' && password === '12345') {
ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
} else {
ctx.response.body = `<h1>Login failed!</h1>
<p><a href="/">Try again</a></p>`;
}
}; module.exports = {
'GET /': fn_index,
'POST /signin': fn_signin
};

这个index.js通过module.exports把两个URL处理函数暴露出来。

类似的,hello.js把一个URL处理函数暴露出来:

var fn_hello = async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
}; module.exports = {
'GET /hello/:name': fn_hello
};

现在,我们修改app.js,让它自动扫描controllers目录,找到所有js文件,导入,然后注册每个URL:

路径分发url

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 先导入fs模块,然后用readdirSync列出文件
var fs = require('fs'); // 这里可以用sync是因为启动时只运行一次,不存在性能问题:
// __dirname === 当前根目录名
// fs.readdirSync 读出文件夹中的文件
var files = fs.readdirSync(__dirname + '/controllers'); // 过滤出.js文件: [ 'hello.js', 'index.js', 'login.js' ]
var js_files = files.filter((f)=>{
return f.endsWith('.js');
}); // 处理每个js文件:
for (var f of js_files) {
// console.log(`process controller: ${f}...`);
// 导入js文件: 当前目录controllers+当前循环文件 { 'GET /hello/:name': [AsyncFunction: fn_hello] }
let mapping = require(__dirname + '/controllers/' + f) for (var url in mapping) {//GET /hello/:name GET / POST /signin
// 如果url以"GET xxx"开头:
if (url.startsWith('GET ')) {
var path = url.substring(4); // 去除字符串前面的4个字符。 GET /(这四个)
//取到路径 path == /hello/:name, mapping[url] == [AsyncFunction: fn_hello]
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith(`POST`)){ //处理post请求
// 去除前面的post加一个空格 POST
var path = url.substring(5);
router.post(path,mapping[url]);
console.log(`register URL mapping: POST ${path}`)
} else {
// 无效的的url
console.log(`invalid URL: ${url}`)
}
}
} // add middlware 这个要放前面
app.use(bodyParser()); // add router middlware
app.use(router.routes()); app.listen(3000)
console.log('app started at port 3000...');

处理请求页面

var fn_login = async (ctx, next)=> {
ctx.response.body = `
<form action="/mark" method="POST">
<input type="text" name="use" value="riven">
<input type="password" name="pwd">
<input type="submit" >
</form>
`
} var fn_login_post = async (ctx,next) => {
var name = ctx.request.body.use || '';
var password = ctx.request.body.pwd ||'';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'riven' && password ==='123456') {
ctx.response.body = `<h1> Welcome,${name}!<h1>`
} else {
ctx.response.body = `<h1>Login failed!<h1>
<p><a href='/'>Try agein</a></p>
`
}
} module.exports = {
'GET /': fn_login,
'POST /mark': fn_login_post
};

如果上面的大段代码看起来还是有点费劲,那就把它拆成更小单元的函数:(简化函数版)

处理url

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 先导入fs模块,然后用readdirSync列出文件
var fs = require('fs'); // 读取文件 处理路径
function fileControllers(router){
// 这里可以用sync是因为启动时只运行一次,不存在性能问题:
// __dirname === 当前根目录名
// fs.readdirSync 读出文件夹中的文件
var files = fs.readdirSync(__dirname + '/controllers'); // 过滤出.js文件: [ 'hello.js', 'index.js', 'login.js' ]
var js_files = files.filter((f)=>{
return f.endsWith('.js');
}); // 处理每个js文件:
for (var f of js_files) {
// console.log(`process controller: ${f}...`);
// 导入js文件: 当前目录controllers+当前循环文件 { 'GET /hello/:name': [AsyncFunction: fn_hello] }
let mapping = require(__dirname + '/controllers/' + f)
requestControllers(router,mapping) }
} // 处理request请求
function requestControllers(router, mapping){
for (var url in mapping) {//GET /hello/:name GET / POST /signin
// 如果url以"GET xxx"开头:
if (url.startsWith('GET ')) {
var path = url.substring(4); // 去除字符串前面的4个字符。 GET /(这四个)
//取到路径 path == /hello/:name, mapping[url] == [AsyncFunction: fn_hello]
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith(`POST`)){ //处理post请求
// 去除前面的post加一个空格 POST
var path = url.substring(5);
router.post(path,mapping[url]);
console.log(`register URL mapping: POST ${path}`)
} else {
// 无效的的url
console.log(`invalid URL: ${url}`)
}
}
} fileControllers(router) // add middlware 这个要放前面
app.use(bodyParser()); // add router middlware
app.use(router.routes()); app.listen(3000)
console.log('app started at port 3000...');

页面

var fn_login = async (ctx, next)=> {
ctx.response.body = `
<form action="/mark" method="POST">
<input type="text" name="use" value="riven">
<input type="password" name="pwd">
<input type="submit" >
</form>
`
} var fn_login_post = async (ctx,next) => {
var name = ctx.request.body.use || '';
var password = ctx.request.body.pwd ||'';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'riven' && password ==='123456') {
ctx.response.body = `<h1> Welcome,${name}!<h1>`
} else {
ctx.response.body = `<h1>Login failed!<h1>
<p><a href='/'>Try agein</a></p>
`
}
} module.exports = {
'GET /': fn_login,
'POST /mark': fn_login_post
};

Controller Middleware

最后,我们把扫描controllers目录和创建router的代码从app.js中提取出来,作为一个简单的middleware使用,命名为controller.js

这样一来,我们在app.js的代码又简化了:

...

// 导入controller middleware:
const controller = require('./controller'); ... // 使用middleware:
app.use(controller());

经过重新整理后的工程url2-koa目前具备非常好的模块化,所有处理URL的函数按功能组存放在controllers目录,今后我们也只需要不断往这个目录下加东西就可以了,app.js保持不变。

login.js 页面

var fn_login = async (ctx, next)=> {
ctx.response.body = `
<form action="/mark" method="POST">
<input type="text" name="use" value="riven">
<input type="password" name="pwd">
<input type="submit" >
</form>
`
} var fn_login_post = async (ctx,next) => {
var name = ctx.request.body.use || '';
var password = ctx.request.body.pwd ||'';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'riven' && password ==='123456') {
ctx.response.body = `<h1> Welcome,${name}!<h1>`
} else {
ctx.response.body = `<h1>Login failed!<h1>
<p><a href='/'>Try agein</a></p>
`
}
} module.exports = {
'GET /': fn_login,
'POST /mark': fn_login_post
};

controllers.js

// 先导入fs模块,然后用readdirSync列出文件
var fs = require('fs'); // 读取文件 处理路径
function fileControllers(router,dir){
// 这里可以用sync是因为启动时只运行一次,不存在性能问题:
// __dirname === 当前根目录名
// fs.readdirSync 读出文件夹中的文件
var files = fs.readdirSync(__dirname + `/${dir}`); // 过滤出.js文件: [ 'hello.js', 'index.js', 'login.js' ]
var js_files = files.filter((f)=>{
return f.endsWith('.js');
}); // 处理每个js文件:
for (var f of js_files) {
// console.log(`process controller: ${f}...`);
// 导入js文件: 当前目录controllers+当前循环文件 { 'GET /hello/:name': [AsyncFunction: fn_hello] }
let mapping = require(__dirname + `/${dir}/` + f)
requestControllers(router,mapping) }
} // 处理request请求
function requestControllers(router, mapping){
for (var url in mapping) {//GET /hello/:name GET / POST /signin
// 如果url以"GET xxx"开头:
if (url.startsWith('GET ')) {
var path = url.substring(4); // 去除字符串前面的4个字符。 GET /(这四个)
//取到路径 path == /hello/:name, mapping[url] == [AsyncFunction: fn_hello]
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith(`POST`)){ //处理post请求
// 去除前面的post加一个空格 POST
var path = url.substring(5);
router.post(path,mapping[url]);
console.log(`register URL mapping: POST ${path}`)
} else {
// 无效的的url
console.log(`invalid URL: ${url}`)
}
}
} module.exports = function (dir){
let
controllers_dir = dir || `controllers` // 如果不传参数,扫描目录默认为'controllers'
// 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')();
fileControllers(router, controllers_dir)
return router.routes() };

app.js

// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 导入controller middleware:
const controller = require('./controller') // add middlware 这个要放前面
app.use(bodyParser()); // 使用middleware: app.use(router.routes())
app.use(controller()); app.listen(3000)
console.log('app started at port 3000...');

经过重新整理后的工程url2-koa目前具备非常好的模块化,所有处理URL的函数按功能组存放在controllers目录,今后我们也只需要不断往这个目录下加东西就可以了,app.js保持不变。

koa web框架入门的更多相关文章

  1. 教程:Visual Studio 中的 Django Web 框架入门

    教程:Visual Studio 中的 Django Web 框架入门 Django 是高级 Python 框架,用于快速.安全及可扩展的 Web 开发. 本教程将在 Visual Studio 提供 ...

  2. Python Flask Web 框架入门

    Python Flask 目录 本文主要借鉴 letiantian 的文章 http://www.letiantian.me/learn-flask/ 一.简介 二.安装 三.初始化Flask 四.获 ...

  3. 比我的脸还干的gan货——Python Flask Web 框架入门

    Flask是一个轻量级的基于Python的web框架. 本文适合有一定HTML.Python.网络基础的同学阅读. 1. 简介 这份文档中的代码使用 Python 3 运行.是的,所以读者需要自己在电 ...

  4. Django Web框架入门

    一.Django介绍 Django是一个开放源代码的Web应用框架,由Python写成,采用了MVC的框架模式.Django的主要目的是简便.快速的开发数据库驱动的网站.它强调代码复用,多个组件可以很 ...

  5. Express NodeJs Web框架 入门笔记

    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...

  6. 最快的 Python Web 框架入门

    速度比较 框架 实现基础 每秒请求数 平均时间 Sanic Python 3.5 + uvloop 30,601 3.23ms Wheezy gunicorn + meinheld 20,244 4. ...

  7. Koa – 更加强大的下一代 Node.js Web 框架

    Koa 是 Express 的开发团队设计的下一代 Web 框架,其目的是为 Web 应用程序提供更小,更具表现力,更坚实的基础.Koa 没有核捆绑任何中间件,并提供了一​​套优雅的方法,使服务器端开 ...

  8. koa : Express出品的下一代基于Node.js的web框架

    https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434501579966a ...

  9. 新一代web框架Koa源码学习

    此文已由作者张佃鹏授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Koa 就是一种简单好用的 Web 框架.它的特点是优雅.简洁.表达力强.自由度高.本身代码只有1000多行 ...

  10. 参考KOA,5步手写一款粗糙的web框架

    我经常在网上看到类似于KOA VS express的文章,大家都在讨论哪一个好,哪一个更好.作为小白,我真心看不出他两who更胜一筹.我只知道,我只会跟着官方文档的start做一个DEMO,然后我就会 ...

随机推荐

  1. Vue的Vue-ls使用

    Vue插件,用于从Vue上下文中使用本地Storage,会话Storage和内存Storage 1. 安装 NPM npm install vue-ls --save YARN yarn add vu ...

  2. Clip-跳过

    在 Stable Diffusion 1.x 模型中,CLIP 用作文本嵌入.CLIP模型由多层组成.他们一层一层地变得更加具体.过于简单化,第一层可以理解"人",第二层可以区分& ...

  3. 张同乐-从零开始,打造高效可靠的Locust性能测试

    一.前言 欢迎来到Locust负载测试的世界!Locust是一款开源的负载测试工具,它可以模拟成千上万的用户同时访问你的应用程序,以测试其性能和稳定性. 这个工具具有易于使用.可扩展和高度可定制化等特 ...

  4. flask blinker信号

    Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为. pip3 install blinker 1.内置信号 request_started = _ ...

  5. Vue——生命周期

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 002. git 分支管理

    git分支 git分支,从本质上来讲仅仅是指向提交对象的可变指针,在这一点上与svn是有着本质区别,svn的分支实际就是个目录而已. git默认分支名字是 master,在多次提交操作后,你其实已经有 ...

  7. 企业级nginx内核优化篇

    1. cpu核心配置 方法1: worker_processes auto; 自动调用[推荐] 方法2: worker_processes 4; 手工配置 检查CPU核心:yum install nu ...

  8. 微信iOS消息拦截插件教程-第一个tweak编译过程

    -安装好theos框架之后,下面用一个简单的例子进行说明编译过程 -新建一个代码目录 -进入terminal,cd到刚才的目录中 1.进入目录 2.执行/opt/theos/bin/nic.pl 3. ...

  9. mkfs.xfs报错 mkfs.xfs: /dev/new/new_box appears to contain an existing filesystem (ext4). mkfs.xfs: Use the -f option to force overwrite.

    在设置逻辑卷文件类型时候报错 mkfs.xfs: /dev/new/new_box appears to contain an existing filesystem (ext4). mkfs.xfs ...

  10. 新手入门html 表格 表单 超链接 图片

    超链接标签 <a></a> A里面的html属性 href="所要跳转到的目标连接" <a href="http:是必须加的"&g ...