npm i -S koa-loa4
// 先切換到/server
目錄下npm i -S xss
// 先切換到/server
目錄下koa-loggerhtml
koa-morgannode
skip
分類,但,可操做性太差koa-log4jsgit
log4js.configure()
log4js.configure({...})
// configure規範對象 { // 自定義日誌等級/修改內部已定義的日誌等級 // 日誌等級:OFF > MARK > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL levels: { ... }, { // 定義日誌輸出類型 (參考文檔:https://github.com/log4js-node/log4js-node/blob/master/docs/appenders.md) appenders: { error: { // type是必選屬性,其它屬性配置依賴於type屬性值 type: 'dateFile', // (dateFile參考文檔:https://github.com/log4js-node/log4js-node/blob/master/docs/dateFile.md) filename: path.resolve(__dirname, 'logs', 'error', 'filename'), // 定義日誌存儲位置,與最終指向的目錄/文件同級:filename推薦不要加後綴名 pattern: '.yyyy-MM-dd.log', // 日誌週期,這裏加上文件後綴 alwaysIncludePattern: true, // alwaysIncludePattern爲true時,纔會實現以pattern規則(如:yyyy-MM-dd)新建文件一天一存 //keepFileExt: true // 沒有像官網說的那樣生效,因此,經過設置pattern值帶後綴文件名來替代 } }, // 預自定義日誌類型:log4js.getLoggeer([category])獲取該類型的日誌實例 categories: { // 必須定義一個默認類型,當沒有匹配的類型時,一概按默認類型處理 default: { }, errorLog: { appenders: ['error'], // 指定日誌輸出類型 // 指定可用的最小日誌等級 level: 'error', //能夠使用OFF > MARK > FATAL > ERROR等級,不能夠使用WARN > INFO > DEBUG > TRACE > ALL等級 enableCallStack: true // 是否打印所屬文件名 & 行號 } } } }
代碼部分,注意轉義github
// 新建文件:/server/config/log.js const path = require('path'); const { checkDirExist } = require('../utils/dir'); // 日誌根目錄 const baseLogDir = path.resolve(\_\_dirname, '../logs'); // 錯誤日誌 const errorDir = 'error'; const errorFileName = 'error'; const errorDirPath = path.resolve(baseLogDir, errorDir); const errorLogPath = path.resolve(errorDirPath, errorFileName); // 訪問日誌 const accessDir = 'access'; const accessFileName = 'access'; const accessDirPath = path.resolve(baseLogDir, accessDir); const accessLogPath = path.resolve(accessDirPath, accessFileName); // 響應日誌 const responseDir = 'response'; const responseFileName = 'response'; const responseDirPath = path.resolve(baseLogDir, responseDir); const responseLogPath = path.resolve(responseDirPath, responseFileName); \[errorDirPath, accessDirPath, responseDirPath\].forEach(p \=> { checkDirExist(p); }) module.exports = { // 定義日誌輸出類型https://github.com/log4js-node/log4js-node/blob/master/docs/appenders.md appenders: { console: { type: 'stdout' }, error: { type: 'dateFile', //https://github.com/log4js-node/log4js-node/blob/master/docs/dateFile.md filename: errorLogPath, // 定義生成文件的路徑。 daysToKeep: 7, // 保存7天日誌,大於7天的,刪除; pattern: '.yyyy-MM-dd.log', alwaysIncludePattern: true, // 只有該屬性設置爲true,纔會以pattern追加劇命名filename // keepFileExt: true //不起做用 }, access: { type: 'dateFile', filename: accessLogPath, daysToKeep: 7, // 保存7天日誌,大於7天的,刪除; pattern: '.yyyy-MM-dd.log', alwaysIncludePattern: true, // 只有該屬性設置爲true,纔會以pattern追加劇命名filename // keepFileExt: true //不起做用 }, response: { type: 'dateFile', filename: responseLogPath, daysToKeep: 7, // 保存7天日誌,大於7天的,刪除; pattern: '\-yyyy-MM-dd.log', alwaysIncludePattern: true, // 只有該屬性設置爲true,纔會以pattern追加劇命名filename // keepFileExt: true //不起做用 } }, // 定義Logger對象類型,用於log4js.getLogger(\[category\]) categories: { default: { appenders: \['console'\], level: 'all' }, errorLogger: { appenders: \['error'\], level: 'error' }, accessLogger: { appenders: \['access'\], level: 'info' }, responseLogger: { appenders: \['response'\], level: 'info' } } };
代碼部分,注意轉義npm
// 新建文件:/server/utils/log.js const log4js = require('koa-log4'); const config = require('../config/log'); //以規範對象開啓日誌功能 log4js.configure(config); // 獲取日誌對象實例 const errorLogger = log4js.getLogger('errorLogger'); const accessLogger = log4js.getLogger('accessLogger'); const responseLogger = log4js.getLogger('responseLogger'); const consoleLogger = log4js.getLogger(); const logUtil = {}; // 封裝錯誤日誌 logUtil.logError \= function (ctx, error, resTime) { if (ctx && error) { errorLogger.error(formatError(ctx, error, resTime)); } }; // 封裝請求日誌 logUtil.logAccess \= function (ctx, resTime) { if (ctx) { accessLogger.info(formatAccessLog(ctx, resTime)); } }; // 封裝響應日誌 logUtil.logResponse \= function (ctx, resTime) { if (ctx) { responseLogger.info(formatRes(ctx, resTime)); } }; logUtil.logInfo \= function (info) { if (info) { consoleLogger.info(formatInfo(info)); } }; const formatInfo \= function (info) { let logText = ''; // 響應日誌開始 logText += '\\n' + '\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* console log start \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*' + '\\n'; // 響應內容 logText += 'console detail: ' + '\\n' + JSON.stringify(info) + '\\n'; // 響應日誌結束 logText += '\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* console log end \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*' + '\\n'; return logText; }; // 格式化響應日誌 const formatRes \= function (ctx, resTime) { let logText = ''; // 響應日誌開始 logText += '\\n' + '\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* response log start \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*' + '\\n'; // 添加請求日誌 logText += formatAccessLog(ctx, resTime); // 響應狀態碼 logText += '\\n' + 'response status: ' + ctx.status + '\\n'; // 響應內容 logText += 'response body: ' + '\\n' + JSON.stringify(ctx.body) + '\\n'; // 響應日誌結束 logText += '\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* response log end \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*' + '\\n'; return logText; }; // 格式化錯誤日誌 const formatError \= function (ctx, err, resTime) { let logText = ''; // 錯誤信息開始 logText += '\\n' + '\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* error log start \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*' + '\\n'; // 添加請求日誌 logText += formatAccessLog(ctx, resTime); // 錯誤名稱 logText += '\\n' + 'err name: ' + err.name + '\\n'; // 錯誤信息 logText += 'err message: ' + err.message + '\\n'; // 錯誤詳情 logText += 'err stack: ' + err.stack + '\\n'; // 錯誤信息結束 logText += '\*\*\*\*\*\*\*\*\*\*\*\*\*\*\* error log end \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*' + '\\n'; return logText; }; // 格式化請求日誌 const formatAccessLog \= function (ctx, resTime) { const { method, originalUrl, ip, query, params, body } = ctx.request; let logText = ''; // 客戶端ip logText += 'request client ip: ' + ip + '\\n'; // 客戶端 logText += 'request userAgent: ' + ctx.header\['user-agent'\] + '\\n'; // 訪問協議 logText += 'request protocol: ' + ctx.protocol + '\\n'; // 訪問方法 logText += 'request method: ' + method + '\\n'; // 請求原始地址 logText += 'request originalUrl: ' + originalUrl + '\\n'; // 請求參數 logText += params ? 'request params: ' + JSON.stringify(params) + '\\n' : ''; logText += query ? 'request query: ' + JSON.stringify(query) + '\\n' : ''; logText += body ? 'request body: ' + JSON.stringify(body) + '\\n' : ''; // 服務器響應時間 logText += 'response time: ' + resTime + '\\n'; return logText; }; module.exports = logUtil;
// 更新文件:在須要使用的地方或統一攔截的地方修改 // 如:/server/app.js ... const logUtil = require('./utils/log'); ... // 錯誤處理 app.use(function(ctx, next){ return next().catch((err) => { logUtil.logError(ctx, err) ...
安全系統很簡單,直接在須要進行xss
攻擊處理的地方,進行一下改進便可api
var xss = require("xss"); var html = xss('<script>alert("xss");</script>');
xss
包會根據預先定義好的規則,轉義標籤,過濾調具備攻擊性的屬性。安全