错误处理
koa 对于找不到的会自动返回404错误
可以用ctx.throw(412) 跑出错误码
编写错误处理中间件
把错误处理的中间件放在中间件链条的最前面
app.use(async (ctx, next) => {
try {
await next()
} catch (err) {
// 运行时错误,都返回500
ctx.status = err.status || status.statusCode || 500
// ctx.body = err.message // 最好返回json形式
ctx.body = {
message: err.message
}
}
})
koa-json-error
返回json信息的错误处理中间件
跨平台 变量中间件 cross-env
在package.json中设置 模拟生产环境
"start": "cross-env NODE_ENV=production node app"
koa -parameter 校验参数中间件
const parameter = require('koa-parameter')
app.use(parameter(app)) // ctx加一个全局的方法帮助我们校验参数
ctx.verifyParams({
name: { type: 'string', required: true } // required 默认为true 可不写
})
博客地址
https://www.jianshu.com/u/84e78d51ad4e
git clone https://github.com/r0oth3x49/udemy-dl.git
cd udemy-dl
pip install -r requirements.txt
python udemy-dl.py 课程地址 -o "存放目录" -q 720 -c 章节编号 -l 章节中课程编号
python udemy-dl.py https://www.udemy.com/ios11-app-development-bootcamp/learn/v4/t/lecture/7626360 -o /Users/chang/Desktop/sketch -q 720 -c 35 -l 8
下载 https://www.udemy.com/ios11-app-development-bootcamp/learn/v4/t/lecture/7626360 课程的第 35 章节的第 8 课到本地目录 /Users/chang/Desktop/sketch 下。视频清晰度为 720。
如果想下载 1080 视频,把 720 改成 1080 即可
python udemy-dl.py https://www.udemy.com/complete-python-bootcamp/learn/lecture/3421822 -o F:\udemy\learn-python -q 720 -c 1 -l 1
=======
云数据库---mongodb Atlas
- 注册用户
- 创建集群
- 添加数据库用户
- 设置IP地址白名单
- 获取连接地址
实操步骤
- www.mongodb.com -- products -- cloud -- mongodb Atlas (https://www.mongodb.com/cloud/atlas)
- 按照get stated 做就好 aws - 选新加坡地址 - 默认存储 - 按照mongodb4.0 - 集群名称要自定义一下,一旦创建就不能修改
- 创建第一个集群是免费的,如果再创建第二个集群就要收费了
- 创建数据库
- 创建用户
- 添加IP地址,选择可以从任何地方访问
连接数据库
const mongoose = require('mongoose')
mongoose.connect(dbUrl, { useNewUrlParser: true }, () => {
console.log('数据库连接成功')
})
mongoose.connection.on('error', () => {
console.log('数据库连接失败')
})
设计用户模块的 Schema (json的数据结构)
- 分析用户模块的属性
- 编写用户模块的 Schema
- 使用Schema 生成用户 Model (MVC中的 Model,通常用于一些数据库的操作)
Schema 应该放在 models文件夹下
+ models
const mongoose = require('mongoose')
const { Schema, model } = mongoose // 可以用这个生成文档 Schema
// 可以设计出非常复杂的嵌套结构
const userSchema = new Schema({
name: {type: String, required: true},
age: {type: Number, default: 0}
})
module.exports = model('User', userSchema) // model 可以来操作数据
用Mongoose类库实现增删改查接口
- User.find()
- User.findById(id)
- new User(ctx.request.body).save()
- User.findByIdAndUpdate(ctx.params.id, ctx.request.body)
- User.findByIdAndRemove(ctx.params.id)
- User.findOne(ctx.params.id)
const User = require('../models/users')
async find(ctx) {
ctx.body = await User.find()
}
认证与授权
session
-
客户端发起请求,携带用户名和密码,服务端接到请求后,生成session数据,保存在内存或者数据库(如redis)中,并把sessionId 返回给前端。
-
前端拿到sessinId后存在cookie中,set-cookie 不止有sessionId还有domain
-
客户端在发起请求,验证session
前端想重新登录,清除缓存即可,后端想重新登录清楚session即可
优点:
- 相比JWT可主动清除cookie
- session 保存在服务端,相对安全
- 结合cookie使用,灵活,兼容性好
缺点:
- cookie + session 跨域场景表现不好
- 如果分布式部署,要做多机共享机制
- 查询session信息可能有数据库操作
JWT
- JSON Web Token 是一个开放的标准(RFC 7519)
- 紧密且独立,作为JSON对象传输
- 该信息可验证和信任,经过数字签名
JWT构成
- 头部(Header)
- typ: token类型,定义为 JWT
- alg: 使用hash算法,如 HMAC SHA256 RSA
- 最后用 base64Url 编码了一下
- 有效载荷(Payload)
- 存储要传递的信息,如用户id, 用户名等
- 还包含元数据,如过期时间, 发布人等
- 与header不同,可加密
- 签名(Signature)
- Header 和 Payload 部分进行签名
- 保证token在传输过程中没有被篡改或损坏
JWT特点
- 通过令牌校验 无状态
- RESTful API
- JWT 性能不好,包含HTTP中完整的信息
- 时效性, JWT只能在过期后清除,不能主动销毁, 不如 session
const jwt = require('jsonwebtoken')
const token = jwt.sign({ name: 'lulu', secret }) // 生成签名
jwt.verify(token) // 经过校验的解码
JWT最主要就是解决跨域问题,存储在客户端,服务端无状态的
上传图片
- 用户头像
- 封面图片
- 问题和回答中的图片(支持富文本,图片可以通过按钮或者复制粘贴来上传)
- 话题图片
上传图片的功能点
- 基础功能: 上传图片,生成图片链接
- 附加功能:限制上传图片的大小和类型(加快图片加载)---通常在前端做
生成图片高中低3中分辨率的图片链接、生成CDN(更好的传输速度)
上传图片的技术方案
- 阿里云 OSS 等云服务,推荐在生产环境使用
- 直接上传到自己的服务器,不推荐在生产环境下使用(不稳定,不支持分布式环境,适合学习)
使用 koa-body 中间件获取上传的文件
- 安装 koa-body 替换 koa-bodyparser(koa-bodyparser只支持json和form两种格式的请求体,不支持文件的格式)
- 设置图片上传目录(在注册koa-body中间件时注册的)
- 使用Postman模拟上传文件
npm install koa-body --save
npm uninstall koa-bodyparser --save // 卸载koa-bodyparser
const kodBody = require('koa-body')
app.use(kodBody({
multipart: true, // 启用文件,支持文件的格式
formidable: {
uploadDir: path.join(__dirname, '/public/uploads'),
// 保留拓展名, 默认是 false
keepExtensions: true
}
}))
+ controllers:
class HomeCtl {
index(ctx) {
ctx.body = '这是主页'
}
upload(ctx) {
// 获取上传文件
const file = ctx.request.files.myfile
ctx.body = { path: file.path }
}
}
+ routes
+ home.js:
const { index, upload } = require('../controllers/home')
const router = new Router()
router.post('/upload', upload)
- postman 里面新建一个 request, 路径为设置的路由,body中选择form-data格式
key 选择file 格式
PS:有点心累,本来这么写的,运行 ctx.request.files就是 undefined
后来可能改了下中间件的位置,就Ok了,我再改回来,还是ok,简直是迷
使用 koa-static 中间件 生成图片链接
可以帮我们生成静态服务,指定了一个文件夹,文件夹下所有的文件都可以通过http服务来访问
public 作为静态服务器
- 安装 koa-static
- 设置静态文件目录(通常设置在public文件夹下)
- 生成图片链接, 想办法让这个链接在上传接口中返回给客户端
app.use(koaStatic(path.join(__dirname, 'public')))
// 图片链接
http://localhost:3000/uploads/upload_05fda00006b536a730d45455dee4d505.png
const basename = path.basename(file.path) // basename 接收一个绝对路径,并返回basename
// ctx.origin 就是 localhost:3000
ctx.body = { path: `${ctx.origin}/uploads/${basename}` }
public下的所有文件都可以通过http来访问,比如如果想放一个Html前端静态页面,放public下也可以通过http访问
编写前端页面上传文件
- 核心就是表单
- 联调测试
<form action="/upload" enctype="multipart/form-data" method="POST">
<input type="file" name='file'>
<button type="submit">上传</button>
</form>
限制上传格式
<input type="file" name='file' accept='image/png, image/jpeg'> 或者
accept='.png, .jpg, .jpeg'
支持所有图片类型文件
accept='image/*'
个人资料需求分析
- 不同类型的属性
- 字段过滤
个人资料的 Schema 设计 (这里指的是json的数据结构)
- 分析个人资料的数据结构
头像存的是url, 在上传图片的时候,存在服务器上,生成url
avatar_url: { type: String }
// 性别:男或女,可枚举字符串 enum 可根据性别给你推荐适合你的产品
gender: { type: String, enum: ['male', 'female'], defaule: 'male', required: true }
headline: { type: String },
locations: { type: [{ type: String }] }, // 字符串数组
business: { type: String }, // 行业
employments: { // 职业经历
type: [{
company: { type: String },
job: { type: String }
}]
},
educations: {
type: [{
school: { type: String },
major: { type: String },
diploma: { type: Number }, // 用数字表示学历
entrance_year: { type: Number },
graduation_year: { type: Number }
}]
}
个人资料的参数校验
- 请求体的校验
- 分析个人资料的数据结构
- 编写代码校验个人资料参数
通常注册的时候,只填写用户名密码就好,
校验参数的代码写在更新个人资料的接口中
字段过滤
- 设置 Schema 默认隐藏字段, 用户列表里面,不能显示太多字段
- 通过查询字符串显示隐藏字段
select: false
// 设置 Schema 时隐藏字段
const { fields } = ctx.query
console.log('find by id', fields)
// 把 f 不存在的字段过滤掉
const selectFields = fields.split(';').filter(f => f).map(item => ' +' + item).join('')
// 把隐藏的字段通过query查询显示出来
const user = await User.findById(ctx.params.id).select(selectFields) // +employments +educations
网友评论