Предисловие:
На этот раз я использую node express jwt для достижения небольшой аутентификации, и медленно добавляются база данных и т. п. Сначала выполните весь процесс, и в основном его можно использовать в проекте. На этот раз мне не нужно компилировать его с помощью gulp, я добавил журнал ошибок log4.js и провел небольшой стресс-тест. Подробно раскрывать не буду, если интересно, можете скачать:гитхаб-адрес
Соответствует переднему концу:Интерфейсная архитектура интерфейса vue+axios реализует перехват входа в систему (перехват маршрутизации, перехват http)
Грубый процесс: каждый раз, когда приходит запрос, он должен пройти через retoken.js, чтобы проверить, есть ли у него заголовок токена, если да, то next(), если нет, вернуть сообщение об ошибке. Конечно, вы также можете установить интерфейс, который не требует аутентификации, а сразу после решения использовать метод next().
1. Структура каталога:
Давайте начнем, config: файл конфигурации, контроллеры: управление маршрутизацией, журналы: журнал ошибок, промежуточное ПО: некоторое промежуточное ПО, модель: взаимодействие с данными, маршрутизатор: распределение маршрутов
2. Напишите app.js
app.js
import express from 'express';
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import session from 'express-session'
import log4js from 'log4js';
import CONFIG from './config';
import api from './router/api'
// import errorHandler from './middleware/logger';
let app = express();
//中间件设置
app.use(cookieParser('sessionCaptcha'))
app.use(session({
secret: 'sessionCaptcha', // 与cookieParser中的一致
resave: true,
saveUninitialized: true,
name: 'USER_INFO_ID'
}))
app.use(bodyParser.urlencoded({extended: false}))
app.use(bodyParser.json())
// 路由
app.use('/', api)
//错误处理
log4js.configure({
appenders: { cheese: { type: 'file', filename: './logs/chen.log' } },
categories: { default: { appenders: ['cheese'], level: 'error' } }
});
const logger = log4js.getLogger('cheese');
//只会记录error级别以上的错误
logger.error('Cheese is too ripe!');
logger.fatal('Cheese was breeding ground for listeria.');
//容错处理机制
app.use(logErrors);
app.use(clientErrorHandler);
app.use(errorHandler);
function logErrors(err, req, res, next) {
console.error('记录日志', err.stack);
next(err);
}
function clientErrorHandler(err, req, res, next) {
if (req.xhr) {
res.status(500).send({ error: 'Something blew up!' });
} else {
next(err);
}
}
function errorHandler(err, req, res, next) {
res.status(500);
res.send('你错了');
}
app.use(function (req, res, next) {
if (res.status(404)) {
res.send('Sorry cant find that!404')
}else{
next()
}
})
var server = app.listen(CONFIG.get('port'), CONFIG.get('url'), () => {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
config> информация о конфигурации index.js
const CONFIG = new Map()
//设置端口
CONFIG.set('port', 3000)
//设置url
CONFIG.set('url', '127.0.0.1')
export default CONFIG
3. Напишите API маршрутизатора
Распределение маршрутизатора api.js
import {Router} from 'express'
import jwt from 'jsonwebtoken'
import retoken from './retoken'
import indexController from '../controllers'
const router = Router()
//设置跨域
router.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Request-Headers:content-type,xfilecategory,xfilename,xfilesize");
res.header("X-Powered-By",' 3.2.1')
if(req.method=="OPTIONS") res.send(200);/*让options请求快速返回*/
else next();
});
//添加token认证
router.use(retoken)
//实现登录
router.use('/login', (req, res, next) => {
console.log(111)
//设置个人信息
const userToken = {
name: '1',
loginAt: +new Date
}
//签发token 指定过期时间2h
const token = jwt.sign(userToken, 'chen', { expiresIn: '2h' });
res.json({
code: 200,
data: token
})
})
router.use('/index', (req, res, next) => {
res.json({
code: 200,
data: 'henhao'
})
})
//路由
router.use('/user',indexController)
export default router
аутентификация токена retoken.js
import jwt from "jsonwebtoken";
import api from "./unLogin";
let unLogin = api.unLogin
export default function (req, res, next) {
let method = req.method.toLowerCase()
let path = req.path
//接口不需要登陆:直接next
//判断method类型,并且是否包含path
if(unLogin[method] && unLogin[method].indexOf(path) !== -1){
console.log('到这里不用验证喔')
return next()
}
const token = req.headers.authorization
// console.log(req.headers)
//没有token值,返回401
if (!token) {
return res.json({
code: 401,
msg: 'you need login:there is no token'
})
}
//认证token
jwt.verify(token, 'chen', (err, decoded) => {
console.log('这边需要验证才行喔')
if(err){
return res.json({
code: 401,
msg: err.msg
})
} else {
// 将携带的信息赋给req.user
req.user = decoded
return next()
}
})
}
Интерфейс unLogin.js, не требующий аутентификации при входе
export default {
unLogin: {
get: [
'/index',
'/user'
],
post: [
'/login'
],
put: [],
delete: [],
}
}
4. Напишите модели контроллеров
controllers>index.js
import express from 'express'
import indexMode from '../model'
let router = express.Router()
router
.get('/', (req, res, next) => {
indexMode.getData(function (data) {
res.json(data)
})
})
.put('/', (req, res, next) => {
res.json({
code:200,
data: 'put'
})
})
export default router
models>index.js
let indexModel={
//这里操作数据库
getData:function (cb) {
var data = {
code:200,
data:{
username:111,
password:222
}
}
cb(data)
}
}
module.exports=indexModel
5. Пакеты, которые необходимо установить
Запустить узел с nedemon
"dependencies": {
"body-parser": "^1.18.3",
"cookie-parser": "^1.4.3",
"express": "^4.16.3",
"express-session": "^1.15.6",
"jsonwebtoken": "^8.3.0",
"log4js": "^3.0.2"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"nodemon": "^1.18.3"
}
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon app.js --exec babel-node --presets es2015,stage-2"
},
После запуска с npm запустите dev
Посетите http://127.0.0.1:3000/index.
Посетите http://127.0.0.1:3000/пользователь
Таким образом реализуется jwt-аутентификация сервера узла и подключение к базе данных.После следующего обновления необходимо выполнить следующий шаг на стороне интерфейса.
6. Используйте рабочее давление
Установить
wrk поддерживает большинство UNIX-подобных систем, но не Windows. Требуется поддержка операционной системой LuaJIT и OpenSSL, но не волнуйтесь, большинство Unix-подобных систем поддерживают. Установить wrk очень просто, просто скачайте исходный код wrk с github и выполните команду make по пути к проекту.
git clone https://github.com/wg/wrk
После make в пути к проекту будет сгенерирован исполняемый файл wrk, после чего его можно будет использовать для проверки давления HTTP.
стресс тест
Введите ./wrk -t8 -c200 -d30s --latency 'http://127.0.0.1:3000/index' в текущем каталоге.
200 соединений с использованием 8 потоков, даhttp://127.0.0.1:3000/index
30 секунд стресс-тестирования
Running 30s test @ http://127.0.0.1:3000/index
8 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
(平均值) (标准差) (最大值)(正负一个标准差所占比例)
Latency 65.99ms 15.58ms 185.51ms 89.74%
(延迟)
Req/Sec 380.14 126.58 505.00 57.24%
(处理中的请求数)
Latency Distribution (延迟分布)
50% 60.90ms
75% 62.99ms
90% 82.57ms
99% 127.67ms
90428 requests in 30.06s, 93.72MB read(30.06秒内共处理完成了90428个请求,读取了93.72MB数据)
Socket errors: connect 0, read 145, write 0, timeout 0
Requests/sec: 3008.58 (平均每秒处理完成3008.58个请求)
Transfer/sec: 3.12MB (平均每秒读取数据3.12MB)