这是一个基于脚手架 create-next-app 的应用
// package.json
"scripts": {
"dev": "node ./server.js",
"build": "next build",
"start": "next start",
"test": "jest"
},
"dependencies": {
"@zeit/next-css": "^1.0.1",
"@zeit/next-less": "^1.0.1",
"classnames": "^2.2.6",
"got": "^11.8.1",
"js-cookie": "^2.2.1",
"koa": "^2.13.0",
"less": "^4.0.0",
"moment": "^2.29.1",
"next": "10.0.3",
"next-compose-plugins": "^2.2.1",
"querystring": "^0.2.0",
"rc-notification": "^4.5.4",
"react": "17.0.1",
"react-dom": "17.0.1",
"rmc-dialog": "^1.1.1",
"umi-request": "^1.3.5"
},
"devDependencies": {
"@types/classnames": "^2.2.11",
"@types/jest": "^26.0.19",
"@types/js-cookie": "^2.2.6",
"@types/koa": "^2.11.6",
"@types/log4js": "^2.3.5",
"@types/next": "^9.0.0",
"@types/node": "^14.14.14",
"@types/react": "^17.0.0",
"babel-plugin-module-resolver": "^4.1.0",
"jest": "^26.6.3",
"ts-jest": "^26.4.4",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
// tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"types": [
"node"
],
"moduleResolution": "node",
"lib": [
"dom",
"es2018"
],
"allowSyntheticDefaultImports": true,
"noImplicitAny": true,
"noUnusedLocals": true,
"removeComments": true,
"resolveJsonModule": true,
"strict": true,
"jsx": "preserve",
"baseUrl": "./",
"paths": {
"@/public/*": [
"public/*"
],
"@/*": [
"src/*"
],
},
"typeRoots": [
"src/**/*.d.ts"
],
"allowJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"isolatedModules": true
},
"include": [
"next-env.d.ts",
"node_modules/@types",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
// next-env.d.ts
/// <reference types="next" />
/// <reference types="next/types/global" />
declare module '*.css';
declare module '*.jpg';
declare module '*.png';
declare module '*.gif';
// 测试模块
declare var test: any;
declare var expect: any;
declare var global: {
pin: string;
}
// next.config.js
const withPlugins = require("next-compose-plugins");
const withCSS = require("@zeit/next-css");
const withLess = require("@zeit/next-less");
const config = {
// all your options here
cssModules: false
};
module.exports = withPlugins([withLess, withCSS], config);
// server.js
const Koa = require('koa')
const next = require('next')
const dev = process.env.NODE_ENV === 'production'
const app = next({dev})
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = new Koa()
server.use(async (ctx, next) => {
await handle(ctx.req, ctx.res)
ctx.respond = false
next()
})
server.listen(3000, () => {
console.log('server is running at http://localhost:3000')
})
})
// Log4Js.ts
import log4js from "log4js";
log4js.configure({
appenders: {
logFile: {
type: "dateFile",
filename: "./logs/logFile", // 你要写入日志文件的路径
alwaysIncludePattern: true, // 将模式包含在当前日志文件的名称及其备份中
pattern: "yyyy-MM-dd-hh.log",
encoding: "utf-8",
maxLogSize: 10240, // 文件最大存储空间
},
logErrorFile: {
type: "dateFile",
filename: "./logs/logFile", // 你要写入日志文件的路径
alwaysIncludePattern: true, // 将模式包含在当前日志文件的名称及其备份中
pattern: "yyyy-MM-dd-hh.error.log",
encoding: "utf-8",
maxLogSize: 10240, // 文件最大存储空间
},
apiLogFile: {
type: "dateFile",
filename: "./logs/apiLogFile", // 你要写入日志文件的路径
alwaysIncludePattern: true, // 将模式包含在当前日志文件的名称及其备份中
pattern: "yyyy-MM-dd-hh.log",
encoding: "utf-8",
maxLogSize: 10240, // 文件最大存储空间
},
apiLogErrorFile: {
type: "dateFile",
filename: "./logs/apiLogFile", // 你要写入日志文件的路径
alwaysIncludePattern: true, // 将模式包含在当前日志文件的名称及其备份中
pattern: "yyyy-MM-dd-hh.error.log",
encoding: "utf-8",
maxLogSize: 10240, // 文件最大存储空间
},
logConsole: {
type: "console",
},
},
categories: {
default: {
appenders: ["logFile"],
level: "all",
},
info: {
appenders: ["logFile"],
level: "all",
},
error: {
appenders: ["logErrorFile"],
level: "error",
},
apiInfo: {
appenders: ["apiLogFile"],
level: "all",
},
apiError: {
appenders: ["apiLogErrorFile"],
level: "error",
},
console: {
appenders: ["logConsole"],
level: log4js.levels.ALL.levelStr,
}
},
});
export default {
info: function(msg: string, ...args: any[]) {
const logger = log4js.getLogger(process.env.mode === "production" ? "info": "console")
logger.info(msg, ...args)
},
debug: function(msg: string, ...args: any[]) {
const logger = log4js.getLogger(process.env.mode === "production" ? "info": "console")
logger.debug(msg, ...args)
},
error: function(msg: string, ...args: any[]) {
const logger = log4js.getLogger(process.env.mode === "production" ? "error": "console")
logger.error(msg, ...args)
},
apiInfo: function(msg: string, ...args: any[]) {
const logger = log4js.getLogger(process.env.mode === "production" ? "apiInfo": "console")
logger.info(msg, ...args)
},
apiDebug: function(msg: string, ...args: any[]) {
const logger = log4js.getLogger(process.env.mode === "production" ? "apiInfo": "console")
logger.debug(msg, ...args)
},
apiError: function(msg: string, ...args: any[]) {
const logger = log4js.getLogger(process.env.mode === "production" ? "apiError": "console")
logger.error(msg, ...args)
},
}
// Crypto.ts
const cryptoUtils = require("crypto");
const DEFAULT_KEY = '16位字符'
const DEFAULT_IV = '16位字符'
interface I_EncodeParam {
key?: string;
plain_text: string;
algorithm?: string;
iv?: string;
autoPadding?: boolean;
input_encoding?:
| "hex"
| "base64"
| "utf8"
| "utf-8"
| "utf16le"
| "latin1"
| "ascii"
| "binary"
| "ucs2"
| "ucs-2"
| undefined;
output_encoding?: "hex" | "base64";
}
interface I_DecodeParam {
key?: string;
encrypted: string;
algorithm?: string;
iv?: string;
autoPadding?: boolean;
input_encoding?: "hex" | "base64";
output_encoding?:
| "hex"
| "base64"
| "utf8"
| "utf-8"
| "utf16le"
| "latin1"
| "ascii"
| "binary"
| "ucs2"
| "ucs-2"
| undefined;
}
export function aesEncrypt(encodeParam: I_EncodeParam): string {
const {
algorithm = "aes-128-cbc",
key = Buffer.from(DEFAULT_KEY, 'utf8'),
iv = Buffer.from(DEFAULT_IV, 'utf8'),
plain_text,
input_encoding = 'utf8',
output_encoding = "hex",
} = encodeParam;
try {
const cipher = cryptoUtils.createCipheriv(algorithm, key, iv);
let crypted = cipher.update(plain_text, input_encoding, output_encoding);
crypted += cipher.final(output_encoding)
return crypted;
} catch (e) {
throw e
}
}
export function aesDecrypt(decodeParam: I_DecodeParam): string {
const {
algorithm = "aes-128-cbc",
key = Buffer.from(DEFAULT_KEY, 'utf8'),
iv = Buffer.from(DEFAULT_IV, 'utf8'),
encrypted,
input_encoding = "utf8",
output_encoding = 'hex',
} = decodeParam;
try{
const decipher = cryptoUtils.createDecipheriv(algorithm, key, iv)
let decrypted = decipher.update(encrypted, output_encoding, input_encoding)
decrypted += decipher.final(input_encoding)
return decrypted;
} catch (e) {
throw e
}
}