从零跟着撸web server后台,来来来

13 阅读3分钟

Vue 编码基础

2.1.1. 组件规范

2.1.2. 模板中使用简单的表达式

2.1.3 指令都使用缩写形式

2.1.4 标签顺序保持一致

2.1.5 必须为 v-for 设置键值 key

2.1.6 v-show 与 v-if 选择

2.1.7 script 标签内部结构顺序

2.1.8 Vue Router 规范

Vue 项目目录规范

2.2.1 基础

2.2.2 使用 Vue-cli 脚手架

2.2.3 目录说明

2.2.4注释说明

2.2.5 其他

开源分享:docs.qq.com/doc/DSmRnRG… const val = await updateBlog(ctx.query.id, ctx.request.body)

if (val) {

ctx.body = new SuccessModel()

} else {

ctx.body = new ErrorModel('更新博客失败')

}

})

router.post('/del', loginCheck, async function (ctx, next) {

const author = ctx.session.username

const val = await delBlog(ctx.query.id, author)

if (val) {

ctx.body = new SuccessModel()

} else {

ctx.body = new ErrorModel('删除博客失败')

}

})

module.exports = router

3. 新建模型

首先解释一下SuccessModel和ErrorModel , 作用主要是供全局返回信息使用的。如登陆成功或者失败返回的标志位及提示信息

class BaseModel{

constructor(data,message){

if(typeof data === 'string'){

this.message = data

data = null

message = null

}

if(data){

this.data = data

}

if(message){

this.message = message

}

}

}

class SuccessModel extends BaseModel{

constructor(data,message){

super(data,message)

this.errno = 0

}

}

class ErrorModel extends BaseModel{

constructor(data,message){

super(data,message)

this.errno = -1

}

}

module.exports = {

SuccessModel,

ErrorModel

}

4. 中间件开发

登陆校验的中间件 loginCheck

其实就是检查 session 中是否存有用户名的信息(信息在登陆成功时写进 session)

const { ErrorModel } = require('../model/resModel')

module.exports = async (ctx, next) => {

if (ctx.session.username) {

await next()

return

}

ctx.body = new ErrorModel('未登录')

}

5. 控制层开发

接下来就讲一下控制层的实现,主要是连接数据库的sql语句来实现数据的交互

const xss = require('xss')

const { exec } = require('../db/mysql')

const getList = async (author, keyword) => {

let sql = select * from blogs where 1=1

if (author) {

sql += and author='${author}'

}

if (keyword) {

sql += and title like '%${keyword}%'

}

sql += order by createtime desc;

return await exec(sql)

}

const getDetail = async (id) => {

const sql = select * from blogs where id='${id}'

const rows = await exec(sql)

return rows[0]

}

const newBlog = async (blogData = {}) => {

// blogData 是一个博客对象,包含 title content author 属性

const title = xss(blogData.title)

const content = xss(blogData.content)

const author = blogData.author

const createTime = Date.now()

const sql = `

insert into blogs (title, content, createtime, author)

values ('title,{title}', '{content}', createTime,{createTime}, '{author}');

`

const insertData = await exec(sql)

return {

id: insertData.insertId

}

}

const updateBlog = async (id, blogData = {}) => {

// id 就是要更新博客的 id

// blogData 是一个博客对象,包含 title content 属性

const title = xss(blogData.title)

const content = xss(blogData.content)

const sql = `

update blogs set title='title,content={title}', content='{content}' where id=${id}

`

const updateData = await exec(sql)

if (updateData.affectedRows > 0) {

return true

}

return false

}

const delBlog = async (id, author) => {

// id 就是要删除博客的 id

const sql = delete from blogs where id='${id}' and author='${author}';

const delData = await exec(sql)

if (delData.affectedRows > 0) {

return true

}

return false

}

module.exports = {

getList,

getDetail,

newBlog,

updateBlog,

delBlog

}

5. 连接数据库

说明一下 exec函数其实就是数据库查询的函数

const mysql = require('mysql')

const { MYSQL_CONF } = require('../conf/db')

//创建链接对象

const con = mysql.createConnection(MYSQL_CONF)

//开始连接

con.connect()

//统一执行sql函数

function exec(sql) {

const promise = new Promise((resolve, reject) => {

con.query(sql, (err, result) => {

if (err) {

reject(err)

return

}

resolve(result);

})

})

return promise

}

module.exports = {

exec,

escape:mysql.escape

}

连接 mysql 的具体配置,分为生产环境和开发环境

const env = process.env.NODE_ENV //获取环境变量

let MYSQL_CONF

if (env === 'dev') {

MYSQL_CONF = {

host: 'localhost',

user: 'root',

port: 3306,

password: 'password',

database: 'myblog'

}

}

if (env === 'production') {

MYSQL_CONF = {

host: 'localhost',

user: 'root',

port: 3306,

password: 'password',

database: 'myblog'

}

}

module.exports = {

MYSQL_CONF

}

项目的WEB安全


1. sql 注入

const sql = select username,realname from users where username=${username} andpassword=${password};

首先我们看一下 sql 的数据库查询,要是用户名输入 zhangsan' --就会把后面的密码注释了(也就是说不用密码就可以登陆)

解决方式是使用 mysql:escape进行转义

2. xss攻击

比如新建博客的时候可能会输入 <script>alert(1)</script>的形式,就会造成xss攻击,解决方式就是转义字符(如<,>等基本可以避免攻击)

const newBlog = async (blogData = {}) => {

// blogData 是一个博客对象,包含 title content author 属性

const title = xss(blogData.title)

const content = xss(blogData.content)

const author = blogData.author

const createTime = Date.now()

const sql = `

insert into blogs (title, content, createtime, author)

values ('title,{title}', '{content}', createTime,{createTime}, '{author}');

`

const insertData = await exec(sql)

return {

id: insertData.insertId

}

}

项目的日志


利用node的文件流,创建一个写文件流,并把它记录到本地文件当中

// logger

app.use(async (ctx, next) => {

const start = new Date()

await next()

const ms = new Date() - start

console.log(${ctx.method} ${ctx.url} - ${ms}ms)

})

const ENV = process.env.NODE_ENV

//记录日志

if (ENV !== 'production') {

app.use(morgan('dev'));

} else {

const logFileName = path.resolve(__dirname, 'logs', 'access.log')

const writeStream = fs.createWriteStream(logFileName, {

flags: 'a'

})

app.use(morgan('combined', {

stream: writeStream

}));

}

中间件原理实现


const http = require('http')

// 组合中间件

function compose(middlewareList) {

return function (ctx) {

// 中间件调用

function dispatch(i) {

const fn = middlewareList[i]

try {

return Promise.resolve(fn(ctx, dispatch.bind(null, i+1)))

} catch(err) {

return Promise.reject(err)

}

}

return dispatch(0)

}

}

class LikeKoa2 {

constructor() {

this.middlewareList = []

}

use(fn) {

this.middlewareList.push(fn)

return this

}

createCtx(req, res) {

const ctx = {

req,

res

}

return ctx

}

handleRequest(ctx, fn) {

return fn(ctx)

}

callback() {

const fn = compose(this.middlewareList)

return (req, res) => {

const ctx = this.createCtx(req, res)

return this.handleRequest(ctx, fn)

}

}

lsiten(...args) {

const server = http.createServer(this.callback())

server.listen(...args)

最后

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】