一、创键项目
1.创建目录 koa2
2.npm init 创建 package.json,然后执行 npm install
3.通过 npm install koa 安装 koa 模块
4.通过 npm install supervisor 安装supervisor模块, 用于node热启动
5.在根目录下中新建 index.js 文件,作为入口文件, 内容如下:
1
2
3
4
5
6
7
8
9
10
11
|
const Koa = require( 'koa' ); // Koa 为一个class
const app = new Koa();
app.use(async (ctx, next) => {
await next();
ctx.response.body = 'Hello, koa2!' ;
});
app.listen(9527, () => {
console.log( 'This server is running at http://localhost:' + 9527)
})
|
6.配置package
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{
"name" : "koa" ,
"version" : "1.0.0" ,
"description" : "" ,
"main" : "koa.js" ,
"scripts" : {
"serve" : "supervisor koa.js"
},
"author" : "" ,
"license" : "ISC" ,
"dependencies" : {
"koa" : "^2.7.0" ,
"supervisor" : "^0.12.0"
}
}
|
7 . 启动
1
|
npm run serve
|
二、路由配置
1
2
3
4
5
6
7
|
cnpm i koa-router
const router = new Router(); // 实例化路由
router.get( '/' , async (ctx, next) => {
ctx.response.body = '<h5>好家伙</h5>' ;
});
app.use(router.routes());
|
路由参数
1
2
3
4
5
6
7
|
//请求地址 www.*****/sss?from=1
router.get( '/hello/:name' , async (ctx, next) => {
var name = ctx.params.name; // 获取请求参数 sss
var from = ctx.query.from; // 1
ctx.response.body = `<h5>好家伙, ${name}!</h5>`;
});
|
三、请求
post
1
2
3
4
5
6
7
8
9
10
|
const bodyParser = require( 'koa-bodyparser' );
app.use(bodyParser());
router.post( '/login' , async (ctx, next) => {
let name = ctx.request.body.name;
let password = ctx.request.body.password;
console.log(name, password);
ctx.response.body = `<h4>好家伙, ${name}!</h4>`;
});
|
get
1
2
3
|
router.get( '/' , async (ctx, next) => {
ctx.response.body = '<h4>好家伙</h4>'
});
|
四、html模板
1、好处
使用html模板,将html从js中分离出去,有助于项目开发和管理。而且,html模板在koa2中,必须通过中间件来实现。
2、koa-views + nunjucks实现html模板
1
2
3
4
5
|
nunjucks.configure(resolve(__dirname, 'views' ), { autoescape: true });
app.use(views(__dirname + '/views' , {
map: { html: 'nunjucks' }
}));
|
五、操作静态资源
1、静态资源在开发中的地位
静态资源环境在服务端是十分常用的一种服务,在后台开发中不仅有需要代码处理的业务逻辑请求,也会有很多的静态资源请求。比如请求js,css,jpg,png这些静态资源请求。也非常的多,有些时候还会访问静态资源路径。
2、koa-static-cache实现静态资源操作
1
2
3
4
5
|
app.use(
staticCache(resolve( "dist" ), {
maxAge: 365 * 24 * 60 * 60
})
)
|
六、进阶
1、结构
入口文件(index.js)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
const Koa = require( 'koa' )
const bodyParser = require( 'koa-bodyparser' );
const staticCache = require( 'koa-static-cache' );
const views = require( 'koa-views' )
const {resolve} = require( 'path' )
const R = require( 'ramda' )
const MIDDLEWARES = [ 'router' ] //中间件配置文件
const nunjucks = require( 'nunjucks' )
const logsUtil = require( '../utils/logs.js' );
//中间件导入 路由导入
const useMiddlewares = (app) => {
R.map(
R.compose(
R.forEachObjIndexed(
initWith => initWith(app)
),
require,
name => resolve(__dirname, `./middlewares/${name}`)
)
)(MIDDLEWARES)
}
;(async () => {
const app = new Koa();
// view engine setup
nunjucks.configure(resolve(__dirname, 'views' ), { autoescape: true });
//views with nunjucks
app.use(views(__dirname + '/views' , {
map: { html: 'nunjucks' }
}));
app.use(bodyParser());
app.use(logsUtil.accessInfo()); //访问日志
//静态资源配置缓存
app.use(
staticCache(resolve( "dist" ), {
maxAge: 365 * 24 * 60 * 60
})
)
app.on( 'error' , err => {
});
app.use(async (ctx,next) => {
await next()
if (parseInt(ctx.status) === 404){
ctx.response.redirect( "/404" )
}
});
await useMiddlewares(app) //导入中间件
app.listen(9527,() => {
console.log( 'Server running on port %d' , 9527);
})
})()
|
2、路由中间件封装
1.新建middlewares文件夹 在下面新建router.js
2.新建lib文件夹 在下面新建decorator.js
3.新建routes下面新建views.js
router.js
1
2
3
4
5
6
7
8
|
const { Route } = require( '../lib/decorator' )
const { resolve } = require( 'path' )
export const router = app => {
const apiPath = resolve(__dirname, '../routes' )
const router = new Route(app, apiPath);
router.init()
}
|
decorator.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
const Router = require( 'koa-router' )
const { resolve } = require( 'path' )
const _ = require( 'lodash' )
const glob = require( 'glob' )
const R = require( 'ramda' )
const symbolPrefix = Symbol( 'prefix' )
const routerMap = new Map()
const isArray = c => _.isArray(c) ? c : [c]
export class Route {
constructor (app, apiPath) {
this .app = app
this .apiPath = apiPath
this .router = new Router()
}
init () {
glob.sync(resolve( this .apiPath, './**/*.js' )).forEach(require)
for (let [conf, controller] of routerMap) {
const controllers = isArray(controller)
let prefixPath = conf.target[symbolPrefix]
if (prefixPath) prefixPath = normalizePath(prefixPath)
const routerPath = prefixPath + conf.path
this .router[conf.method](routerPath, ...controllers)
}
this .app.use( this .router.routes())
this .app.use( this .router.allowedMethods())
}
}
const normalizePath = path => path.startsWith( '/' ) ? path : `/${path}`
const router = conf => (target, key, descriptor) => {
conf.path = normalizePath(conf.path)
routerMap.set({
target: target,
...conf
}, target[key])
}
export const controller = path => target => (target.prototype[symbolPrefix] = path)
export const get = path => router({
method: 'get' ,
path: path
})
export const post = path => router({
method: 'post' ,
path: path
})
export const put = path => router({
method: 'put' ,
path: path
})
export const del = path => router({
method: 'delete' ,
path: path
})
export const use = path => router({
method: 'use' ,
path: path
})
export const all = path => router({
method: 'all' ,
path: path
})
|
view.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
const { controller, get } = require( '../lib/decorator' )
@controller( '' )
export class viewController {
@get( '/' )
async home(ctx, next) {
await ctx.render( 'index' , {
})
}
@get( '/service' )
async enter(ctx, next) {
await ctx.render( 'service' , {
title: '' ,
})
}
@get( '/404' )
async pageNUll(ctx, next) {
await ctx.render( '404' , {
title: ' ' ,
})
}
}
|
3、日志文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
cnpm i koa-log4
config/logs.jsvar path = require( 'path' );
//日志根目录
var baseLogPath = path.resolve(__dirname, '../logs' )
/*报错输出日志*/
//错误日志目录、文件名、输出完整路径
var errorPath = "/error" ;
var errorFileName = "error" ;
var errorLogPath = baseLogPath + errorPath + "/" + errorFileName;
/*请求数据得到响应时输出响应日志*/
//响应日志目录、文件名、输出完整路径
var responsePath = "/response" ;
var responseFileName = "response" ;
var responseLogPath = baseLogPath + responsePath + "/" + responseFileName;
/*操作数据库进行增删改等敏感操作记录日志*/
//操作日志目录、文件名、输出完整路径
var handlePath = "/handle" ;
var handleFileName = "handle" ;
var handleLogPath = baseLogPath + handlePath + "/" + handleFileName;
/*访问级别日志*/
var accessPath = "/access"
var accessFileName = "access" ;
var accessLogPath = baseLogPath + accessPath + "/" + accessFileName;
/*访问级别日志*/
var reqPath = "/req"
var reqFileName = "req" ;
var reqLogPath = baseLogPath + reqPath + "/" + reqFileName;
module.exports = {
//日志格式等设置
appenders:
{
"rule-console" : { "type" : "console" },
"errorLogger" : {
"type" : "dateFile" ,
"filename" : errorLogPath,
"pattern" : "-yyyy-MM-dd.log" ,
"alwaysIncludePattern" : true ,
"encoding" : "utf-8" ,
"path" : errorPath
},
"resLogger" : {
"type" : "dateFile" ,
"filename" : responseLogPath,
"pattern" : "-yyyy-MM-dd.log" ,
"alwaysIncludePattern" : true ,
"encoding" : "utf-8" ,
// "maxLogSize": 204800,
// "numBackups": 3,
"path" : responsePath
},
"handleLogger" : {
"type" : "dateFile" ,
"filename" : handleLogPath, //生成文件路径和文件名
"pattern" : "-yyyy-MM-dd.log" ,
"alwaysIncludePattern" : true ,
"encoding" : "utf-8" ,
// "maxLogSize": 204800,
// "numBackups": 3,
"path" : handlePath
},
"accessLogger" : {
"type" : "dateFile" ,
"filename" : accessLogPath,
"pattern" : "-yyyy-MM-dd.log" ,
"alwaysIncludePattern" : true ,
"encoding" : "utf-8" ,
// "maxLogSize": 204800,
// "numBackups": 3,
"path" : accessPath
},
"reqLogger" : {
"type" : "dateFile" ,
"filename" : reqLogPath,
"pattern" : "-yyyy-MM-dd.log" ,
"alwaysIncludePattern" : true ,
"encoding" : "utf-8" ,
// "maxLogSize": 204800,
// "numBackups": 3,
"path" : reqPath
},
},
//供外部调用的名称和对应设置定义
categories: {
"default" : { "appenders" : [ "rule-console" ], "level" : "all" },
"resLogger" : { "appenders" : [ "resLogger" ], "level" : "info" },
"errorLogger" : { "appenders" : [ "errorLogger" ], "level" : "error" },
"handleLogger" : { "appenders" : [ "handleLogger" ], "level" : "all" },
"accessLogger" : { "appenders" : [ "accessLogger" ], "level" : "all" },
"reqLogger" : { "appenders" : [ "reqLogger" ], "level" : "error" }
},
"baseLogPath" : baseLogPath
}
|
log.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
var log4js = require( 'koa-log4' );
var logsConfig = require( '../config/logs.js' );
//加载配置文件
log4js.configure(logsConfig);
//调用预先定义的日志名称
var resLogger = log4js.getLogger( "resLogger" );
var errorLogger = log4js.getLogger( "errorLogger" );
var handleLogger = log4js.getLogger( "handleLogger" );
var reqLogger = log4js.getLogger( "reqLogger" );
var consoleLogger = log4js.getLogger();
exports.accessInfo = () => log4js.koaLogger(log4js.getLogger( 'accessLogger' )); //访问日志
exports.logInfo = (data) => {consoleLogger.info(data)}
.............
.............
|
关于pm2自动部署 webpack打包 以及数据库后续有时间更新
欢迎干饭人一起推动优化
最后附上工具人地址:https://gitee.com/angry2bird/node-koa
到此这篇关于node koa2 ssr项目搭建的方法步骤的文章就介绍到这了,更多相关node koa2 ssr项目搭建内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/6904833281045299213