跳到主要内容

koa-javaScript

一、初始化


npm init -y

二、安装依赖


2.1 Koa 依赖

npm i koa koa-static koa-router koa-body

2.2 其他依赖

npm install bluebird chalk moment nodemon ora require-all -S

2.3 ES6Model 依赖

npm i babel-polyfill babel-plugin-add-module-exports babel-preset-es2015 babel-preset-stage-3 babel-register -D

2.4 Mongoose 依赖

npm install mongoose -D

三、构建命令


3.1 index.js

require('babel-register')({
presets: ["es2015", "stage-3"],
plugins: ["add-module-exports"]
})
require('babel-polyfill')
const app=require('./src/app.js');
module.exports=app;

3.2 bin/www

bin/www
#!/usr/bin/env node

const http = require('http');
const app = require('../index');
const debug = require('debug')('demo:server');
const server = http.createServer(app.callback());
const {getIPAdress}=require('../src/utils/host');
const {serverMsg}=require('../src/config/chalk');
const port = normalizePort(process.env.PORT || '4000');


server.listen(port,()=>{
console.log(serverMsg(getIPAdress(),port));
});
server.on('error', onError);
server.on('listening', onListening);



function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

四、构建配置


4.1 config/index.js

/**
* @description: 域名访问白名单
*/
export const AllowOrigin = [
"http://localhost:8090",
"https://bolawen.com",
"http://localhost:8080",
"http://localhost:3000",
]
/**
* @description: 服务地址
*/
export const ServerURL = {
// 静态资源服务地址
assetsImage: "https://bolawen.com/resource/image/",
// 接口服务生产地址
production: "https://bolawen.com/server-koa",
// 接口服务开发地址
development: "http://localhost:4000",
};
/**
* @description: JWT sccret
*/
export const Secret = 'bolawen';
/**
* @description: MongoDB 连接地址
*/
export const MongoDBURL = "mongodb://1.116.70.238/admin";
/**
* @description: Assets 文件目录相对于根目录位置
*/
export const ImagePath = "../resource/image/";
/**
* @description: Assets 文件目录映射
*/
export const AssetsImagesDir = {
a:["all","鬼刀","其他"],
g:[]
}
/**
* @description: Referer 白名单
*/
export const Referer = ["bolawen.cn", "bolawen.com", "localhost"];
/**
* @description: GitHub 仓库Map
*/
export const Repository = {
"blog-docusaurus-webpack": "../blog-docusaurus-webpack",
"blog-vuepress-webpack": "../blog-vuepress-webpack",
resource: "../resource",
collect: "../collect",
"bolawen.github.io": "../bolawen.github.io",
};

4.2 config/chalk.js

const chalk=require('chalk');
const moment=require('moment');

/**
* @description: Log提示语
*/

const logMsg=(method,url,query,body)=>{
let argus=JSON.stringify(method=='POST'?body:query);
argus=argus.length>150?argus.slice(0,150)+'…………':argus;

return `
${chalk.green('✨✨✨请求成功!')}

${chalk.yellow('==============')}${chalk.green('请求日志')}${chalk.yellow('==============')}

${chalk.blue('请求时间:')}${chalk.magenta(moment(new Date()).format("YYYY-MM-DD HH:mm:ss"))}
${chalk.blue('请求方式:')}${chalk.magenta(method)}
${chalk.blue('请求路径:')}${chalk.magenta(url)}
${chalk.blue('请求参数:')}${argus}

${chalk.yellow('=====================================')}
`
}

/**
* @description: 服务提示语
*/
const serverMsg=(ip,port)=>{
return `
${chalk.green('✨✨✨服务启动成功!')}

${chalk.yellow('===============================')}

${chalk.cyan("- Local:")} ${chalk.magenta(`http://localhost:${port}`)}
${chalk.cyan("- Host:")} ${chalk.magenta(`http://${ip}:${port}`)}

${chalk.yellow('===============================')}
`
}

/**
* @description: MongoDB 连接提示语
*/

const mongooseMsg=(type,msg)=>{
switch(type){
case "connected":
return `
${chalk.green('✨✨✨MongoDB 连接成功!')}

${chalk.yellow('===============================')}

${chalk.blue('连接地址为:')}${chalk.magenta(msg)}

${chalk.yellow('===============================')}
`
case "error":
return `
${chalk.red('MongoDB 连接失败!')}

${chalk.yellow('===============================')}

${chalk.blue('连接原因为:')}${chalk.magenta(msg)}

${chalk.yellow('===============================')}
`
case "disconnected":
return `
${chalk.yellow('MongoDB 连接断开!')}
`
}
}

/**
* @description: GitHub 更新代码提示语
*/

const gitMsg=(msg)=>{
return `

${chalk.yellow(msg+"成功!")}

`
}

module.exports={
logMsg,
gitMsg,
serverMsg,
mongooseMsg
}

六、构建路由


6.1 git

import Router from 'koa-router';
import log from '../middleware/log';
import GitController from '../controller/git'

const router=new Router({prefix:"/git"});
router.post('/gitHook',log,GitController.gitHook);
module.exports=router

6.2 img

import Router from 'koa-router';
import ImageController from '../controller/image'
import antiStealingLink from '../middleware/antiStealingLink'

const router=Router({prefix:'/image'});
router.get('/bg',antiStealingLink,ImageController.bg)
router.get('/one',antiStealingLink,ImageController.one);
module.exports=router;

6.3 user

import Router from 'koa-router';
import Log from '../middleware/log'
import UserController from '../controller/user';

const router=new Router({prefix:'/user'});

router.post('/add',Log,UserController.add);
router.post('/remove',Log,UserController.remove);
router.post('/edit',Log,UserController.edit);
router.get('/list',Log,UserController.find);
router.get('/detail',Log,UserController.findOne);

module.exports=router;

七、构建数据


7.1 user

import mongoose from '../db/mongodb'

const Schema=mongoose.Schema;
const UserSchma=new Schema({
userName:String,
age:{
type:Number,
min:18,
max:99
},
phone:Number,
createTime:{
type:Date,
default:Date.now
},
updateTime:{
type:Date,
default:Date.now
}
});

const User=mongoose.model('User',UserSchma,'User');
export default User;

八、构建数据库


8.1 db/mongodb

import mongoose from "mongoose";
import { mongoDBURL } from "../config";
import {mongooseMsg} from '../config/chalk'

mongoose.Promise = require('bluebird');
mongoose.connect(mongoDBURL, {
useNewUrlParser: true
});
mongoose.connection.on('connected',function(){
console.log(mongooseMsg('connected',mongoDBURL));
});
mongoose.connection.on('error',function(error){
console.log(mongooseMsg('error',error));
});
mongoose.connection.on('disconnected',function(){
console.log(mongooseMsg('disconnected'));
});

export default mongoose

九、构建控制器


9.1 git

import ora from 'ora';
import process from 'child_process';
import {rootPath} from '../utils/root';
import { Repository } from '../config';
import {gitMsg} from '../config/chalk';

function Command(msg, cmd, operation, repository) {
const spinner = ora(msg);
spinner.start();
const cwd = { cwd: rootPath(repository)};
return new Promise((resolve) => {
const compile = process.spawn(cmd, operation, cwd);
compile.stderr.on('data',res=>{
console.log('\t'+res);
});
compile.stdout.on('data',res=>{
console.log('\t'+res);
});
compile.on('exit',(res)=>{
spinner.succeed();
console.log(gitMsg(msg));
resolve(res);
});
compile.on("close", (res) => {
resolve(res);
});
compile.on('error',(res)=>{
resolve(res);
})
});
}

async function CommandGitFetch(repository) {
return await Command(
"Fetch 代码",
"git",
["fetch", "--all"],
Repository[repository]
);
}

async function CommandGitReset(repository) {
return await Command(
"Reset 代码",
"git",
["reset", "--hard","origin/master"],
Repository[repository]
);
}
async function CommandGitPull(repository) {
return await Command(
"Pull 代码",
"git",
["pull", "origin", "master"],
Repository[repository]
);
}

class GitController {
static async gitHook(ctx){
const {repository:{name}}=ctx.request.body;
await CommandGitFetch(name)
await CommandGitReset(name);
await CommandGitPull(name);
return ctx.body={
code:200,
msg:'更新成功!'
}
}
}

export default GitController;

9.2 img

import fs from 'fs';
import { ImagePath } from '../config';
import {rootPath} from '../utils/root';

const dirPath=rootPath(ImagePath);
const fileList=fs.readdirSync(dirPath);


function getOneOfList(){
const imageTotal=fileList.length;
return Math.floor(Math.random()*(imageTotal-0+1))+0;
}
function getIndexOfTotal(index,total){
const imageTotal=fileList.length;
const groupTotal=Math.floor(imageTotal/total);
const restTotal=imageTotal%total;
const rangeStart=index*groupTotal;
let rangeEnd=rangeStart+groupTotal-1;
if(index+1==total){
rangeEnd=rangeEnd+restTotal;
}
return Math.floor(Math.random()*(rangeEnd-rangeStart+1))+rangeStart;
}

class ImageController{
static async bg(ctx){
ctx.set('Content-Type','image/jpg');
const imageName=getOneOfList();
const imageFile=fs.readFileSync(dirPath+"/"+imageName+'.jpg');
return ctx.body=imageFile;
}
static async one(ctx){
ctx.set('Content-Type','image/jpg');
const {index,total}=ctx.request.query;
const imageName=getIndexOfTotal(index,total);
const imageFile=fs.readFileSync(dirPath+"/"+imageName+'.jpg');
return ctx.body=imageFile;
}
}

export default ImageController;

9.3 user

import User from '../model/user'

class UserController{
static async add(ctx){
const {userName,age,phone}=ctx.request.body;
const filter={userName};
const isHave=await User.findOne(filter);
if(isHave){
return await UserController.edit(ctx);
}
const user=new User({
userName:userName,
age:age,
phone:phone
});
const result=await user.save();
if(result){
return await UserController.findOne(ctx);
}else{
return ctx.body={
code:1,
msg:'添加失败!',
}
}
}
static async remove(ctx){
const {userName}=ctx.request.body;
const filter={userName};
const {deletedCount}=await User.deleteOne(filter);
if(deletedCount>0){
return ctx.body={
code:0,
msg:'删除成功!',
}
}else{
return ctx.body={
code:1,
msg:'删除失败!',
}
}
}
static async edit(ctx){
const {userName,age,phone}=ctx.request.body;
const filter={userName};
const update={age,phone};
const {acknowledged,modifiedCount}=await User.updateOne(filter,update);
if(!acknowledged){
return ctx.body={
code:1,
msg:'没有该条数据'
}
}
if(modifiedCount<1){
return ctx.body={
code:1,
msg:'没有任何改动'
}
}
await UserController.findOne(ctx);
}
static async find(ctx){
const result=await User.find({});
ctx.body={
code:200,
msg:'查询成功',
data:result
};
}
static async findOne(ctx){
const userName=ctx.request.query.userName||ctx.request.body.userName;
const filter={userName}
const result=await User.findOne(filter);
if(result){
return ctx.body={
code:0,
msg:'查询成功!',
data:result
}
}else{
return ctx.body={
code:1,
msg:'查询失败!',
}
}
}
}

export default UserController;

十、构建中间件


10.1 跨域

module.exports=async(ctx,next) =>{
ctx.set("Access-Control-Allow-Origin","*");
ctx.set("Access-Control-Allow-Headers",'*');
ctx.set("Access-Control-Allow-Methods",'"PUT,POST,GET,DELETE,OPTIONS');
ctx.set("Content-Type",'*');
await next();
}

10.2 日志

const {logMsg} =require('../config/chalk');

module.exports = async (ctx, next) => {
const { method, url, query, body } = ctx.request;
console.log(logMsg(method,url,query,body));
await next();
};

10.1 防盗链

antiStealingLink
const fs=require('fs');
import { DefaultImagePath,Referer } from '../config';
import {rootPath} from '../utils/root';

const dirPath=rootPath(DefaultImagePath);
const file=fs.readFileSync(dirPath+'/404.png');

module.exports=async (ctx,next)=>{
const referer=ctx.request.header.referer;
if(!referer){
ctx.set('Content-Type','image/jpg');
ctx.body=file;
return
}
const result=Referer.some(value=>{
return referer.includes(value)==true;
});
if(!result){
ctx.set('Content-Type','image/jpg');
ctx.body=file;
return
}
await next();
}

十一、构建工具函数


11.1 host

const OS=require('os');

const getIPAdress=()=>{
const interfaces = OS.networkInterfaces();
for (let devName in interfaces) {
let iface = interfaces[devName];
for (let i = 0; i < iface.length; i++) {
let alias = iface[i];
if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
return alias.address;
}
}
}
}

module.exports={
getIPAdress
}

11.2 root

import Path from 'path';
export const rootPath=(path)=>{
return Path.join(process.cwd(),path);
}

十二、构建全局入口


import './db/mongodb'
import Koa from "koa";
import koaBody from "koa-body";
import cors from './middleware/cors';
import requireAll from 'require-all';
import { rootPath } from "./utils/root";

const app = new Koa();

app.use(koaBody({ multipart: true }));
app.use(cors);

const routerList=requireAll(rootPath('./src/router'));
Object.keys(routerList).forEach(router=>{
app.use(routerList[router].routes()).use(routerList[router].allowedMethods());
})
export default app;

十三、管理依赖、命令


{
"name": "Node",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "npm run dev",
"dev": "./node_modules/.bin/nodemon bin/www",
"prd": "pm2 start bin/www"
},
"dependencies": {
"bluebird": "^3.7.2",
"chalk": "^4.1.1",
"koa": "^2.13.1",
"koa-body": "^4.2.0",
"koa-router": "^10.0.0",
"moment": "^2.29.1",
"mongoose": "^6.0.12",
"nodemon": "^2.0.14",
"ora": "^5.4.1",
"require-all": "^3.0.0"
},
"devDependencies": {
"babel-polyfill": "^6.26.0",
"babel-plugin-add-module-exports": "^1.0.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-stage-3": "^6.24.1",
"babel-register": "^6.26.0"
}
}