# koa
cnpm i --save koa
# 初步使用
const koa = require('koa')
const app = new koa()
app.use(async (ctx,next)=>{
await next()
ctx.response.type='text/html'
ctx.response.body='<p>2019!!!</p>'
})
/*它的作用是:每收到一个 http 请求,Koa 都会调用通过 app.use() 注册的 async 函数,
同时为该函数传入 ctx 和 next 两个参数。而这个 async 函数就是我们所说的中间件*/
app.listen(3000,()=>{
console.log("ok")
})
# Context对象
上下文,用于确定一次请求的环境。
koa将nodejs中请求( request )和相应( response )对象封装到Context对象中,所以可以把Context对象称为一次对话的上下文,通过加工Context对象,就可以返回给用户的内容。
app.use(async ctx=>{
ctx,
//this,//ctx,this,都是指向ctx
})
# 常用属性和方法
app.use(async (ctx,next)=>{
ctx.response.body={
url:ctx.request.url,
query:ctx.request.query,
querystring:ctx.request.querystring
}
})
浏览器地址栏:http://localhost:3000/demo?id=098&name=wei,显示界面结果如下
{
"url":"/demo?id=098&name=wei",
"query":{"id":"098","name":"wei"},
"querystring":"id=098&name=wei"
}
# ctx.request
koa没有封装获取post参数的方法,需要解析Context中原生node的req,调用 ctx.req
app.use(async (ctx,next)=>{
let postData="";
ctx.req.on('data',(data)=>{
postData+=data
})
ctx.req.on('end',()=>{
console.log(postData)
})
})
//用gitbash模拟请求
//-d表示post请求
//curl -d 'name=lili&age=20' http://localhost:3000
//在启动的cmd窗口打印出 name=lili&age=20
# ctx.request.method
判断请求方式
app.use(async (ctx,next)=>{
console.log(ctx.method===ctx.request.method)//true
console.log(ctx.url===ctx.request.url)//true
console.log(ctx.type===ctx.response.type)//true
console.log(ctx.body===ctx.response.body)//true
if(ctx.request.method==='POST'){
ctx.response.body="post"
}else if(ctx.request.method==='GET'){
ctx.response.body="get"
}else{
ctx.response.body="helloworld"
}
})
# ctx.request.path
请求路径
# ctx.response
| response | 作用 |
|---|---|
| ctx.response.body | 用于设置返回给用户响应主体 |
| ctx.response.status | 设置请求状态(200/404/500) |
| ctx.response.type | 可以设置响应Content-Type |
| ctx.response.redirect | 重定向ctx.response.redirect(url,[alt]) |
ctx.response.type:
- 如果返回内容是html,ctx.response.type='html';
- png图片ctx.response.type='image/png';
- 默认ctx.response.type='text/plain';
- ctx.response.type='txt',txt文件
app.use(async (ctx,next)=>{
ctx.response.status=200;
if(ctx.request.accepts('json')){
console.log('json')
ctx.response.type='json';
ctx.response.body={data:'hello world'}
}else if(ctx.request.accepts('html')){
ctx.response.type='html';
ctx.response.body='<h1>hello</h1>'
}else{
ctx.response.type='txt';
ctx.response.body='hello'
}
})
ctx.response.accepts()用来判断期望接受类型, ctx.response.is(types...) 和其类似,不过它是用来检查响应类型是否是提供的其中之一
# ctx.state
通过 state 可以存储一些数据,比如用户数据,版本信息等。
ctx.state.user = yield User.find(id) ;
//把user属性放到ctx.state对象中,以便能被另一个中间件读取
# ctx.cookies
用于获取和设置cookie
ctx.cookies.get(name,[options]);
ctx.cookies.set(name,value,[options]);
options配置
| key | value |
|---|---|
| maxAge | 一个以毫秒为单位的数字,表示cookie过去时间 |
| signed | cookie签名值 |
| expires | cookie的过期的Date |
| path | cookie路径,默认/ |
| domain | cookie域名 |
| secure | 安全cookie,只能使用https访问 |
| httpOnly | 如果为true,cookie无法被js获取 |
| overwrite | 一个布尔值,表示是否覆盖之前同名的cookie,默认false |
# ctx.throw
app.use(async (ctx,next)=>{
ctx.throw(404)
})
抛出错误,给用户返回信息
# koa中间件
const met=async (ctx,next)=>{
if(ctx.method==='POST'){
ctx.response.body="post"
}else if(ctx.method==='GET'){
ctx.response.body="get1"
}else{
ctx.response.body="helloworld"
}
}
app.use(met)
met就是一个中间件,app.use是加载中间件
中间件函数有两个内置参数ctx、next
next 参数的作用是将处理的 控制权 转交给下一个中间件,用await是因为返回的是个promise,而 next() 后面的代码,将会在下一个中间件及后面的中间件(如果有的话)执行结束后再执行。
注意: 中间件的顺序很重要!
// 记录执行的时间
app.use(async (ctx, next) => {
console.log('中间件1 doSomething')
await next();
console.log('中间件1 end')
})
app.use(async (ctx, next) => {
console.log('中间件2 doSomething')
await next();
console.log('中间件2 end')
})
app.use(async (ctx, next) => {
console.log('中间件3 doSomething')
await next();
console.log('中间件3 end')
})
//中间件1 doSomething
//中间件2 doSomething
//中间件3 doSomething
//中间件3 end
//中间件2 end
//中间件1 end
app.use(async (ctx, next) => {
console.log('中间件1 doSomething')
await next();
console.log('中间件1 end')
})
app.use(async (ctx, next) => {
console.log('中间件2 doSomething')
console.log('中间件2 end')
})
app.use(async (ctx, next) => {
console.log('中间件3 doSomething')
await next();
console.log('中间件3 end')
})
//中间件2缺next,所以后面的中间件3就不执行了
//中间件1 doSomething
//中间件2 doSomething
//中间件2 end
//中间件1 end
# koa-compose
多个中间件组合成单一中间件,便于重用和导出
async function k1(ctx, next) {
console.log('中间件1 doSomething')
await next();
console.log('中间件1 end')
}
async function k2(ctx, next) {
console.log('中间件2 doSomething')
console.log('中间件2 end')
}
async function k3(ctx, next) {
console.log('中间件3 doSomething')
await next();
console.log('中间件3 end')
}
const all =compose([k1,k2,k3])
app.use(all)
//中间件1 doSomething
//中间件2 doSomething
//中间件2 end
//中间件1 end
# koa常用中间件
# koa-router
通过ctx.method方法判断路由相对而言还是麻烦,所以引用koa-router
cnpm install --save koa-router
const koa = require('koa')
const compose=require('koa-compose')
const bodyParser=require('koa-bodyparser')
const Router=require('koa-router')
const app = new koa()
const router= new Router()
router.get('/',(ctx,next)=>{
ctx.type='html';
let html=`
<h1>登录</h1>
<form method='POST' action='/'>
<p>用户名</p>
<input name='username'/><br>
<p>密码</p>
<input name='password'/><br>
<button type='submit'>提交</button>
</form>
`;
ctx.body=html
})
router.post('/',(ctx,next)=>{
let postData=ctx.request.body;
ctx.body=postData
})
app
.use(bodyParser())
.use(router.routes())
.use(router.allowedMethods())
app.listen(3000,()=>{
console.log("ok")
})
//显示界面,get方式,然后输入了数据提交后变成了json
注意
- const Router=require('koa-router')
- Router=require('koa-router')
- app .use(bodyParser()) .use(router.routes()) .use(router.allowedMethods())
router.routes()
# koa-static 与 koa-views
- koa-static:专门用于加载静态资源的中间件
- koa-views:加载html模板文件
cnpm i --save koa-static koa-views
暂缺
# koa电商项目
# vue-cli 2.0版本
//全局安装 vue-cli
cnpm install --global vue-cli
//创建一个基于 webpack 模板的新项目
vue init webpack my-project
# 安装stylus
cnpm install stylus stylus-loader --save-dev
# 验证
<style scoped lang="stylus">
#app
background green
</style>
# 配置ui框架
参考 koa学习之前端ui框架vant
# 移动端适配
- 固定高度宽度百分比
- 媒体查询
- flex布局+rem(font size of the root element:相对根元素的font-size的计算值倍数)
(function(){
var screenW = document.documentElement.offsetWidth||document.body.offsetWidth;
var oHtml = document.getElementsByTagName("html")[0];
oHtml.style.fontSize = 100*(screenW/750)+"px";
})();
(function(){
var screenW = document.documentElement.offsetWidth||document.body.offsetWidth;
var oHtml = document.getElementsByTagName("html")[0];
oHtml.style.fontSize = (screenW/20)+"px";
})();
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
# 快捷插件
vue vscode snippets
# 模拟数据
easymock 可以,但没必要!如果有个完整的json格式文件,也可以用用。
# 重置css
body,html,#app{
width:100%;
height:100%;
font-size:0.32rem;
background:#F2F2F2;
}
a, blockquote, body, code, dd, div, dl, dt, em, fieldset, form, h1, h2, h3, h4, h5, h6, iframe, img, input, label, li, object, ol, p, q, small, span, strong, table, tbody, td, th, tr, ul {
margin: 0;
padding: 0;
border: 0;
}
i,b{
font-style:normal;
font-weight:normal
}
[v-cloak] {
display: none;
}
# 滑动区域
npm install vue-awesome-swiper --save
- 全局引入 //mainjs
import Vue from 'vue'
import VueAwesomeSwiper from 'vue-awesome-swiper'
// require styles
import 'swiper/dist/css/swiper.css'
Vue.use(VueAwesomeSwiper, /* { default global options } */)
- 局部引入
import 'swiper/dist/css/swiper.css'
import { swiper, swiperSlide } from 'vue-awesome-swiper'
export default {
components: {
swiper,
swiperSlide
}
}
# 安装mongodb
安装mongodb后,再配上可视化操作界面(激活)
# Koa用Mongoose连接数据库
Mongoose 是一个开源的封装好的实现Node和MongoDB数据通讯的 数据建模库 ,帮助我们完成数据库的操作和通讯。
npm install mongoose --save
npm install glob --save
# Schema
建模,也就是定义Schema,他相当于MongoDB数据库的一个映射。Schema是一种以文件形式存储的数据库模型骨架,无法直接通往数据库端,也就是说它不具备对数据库的操作能力。Schema是以key-value形式Json格式的数据。
# Schema中的数据类型
- String :字符串类型
- Number :数字类型
- Date : 日期类型
- Boolean: 布尔类型
- Buffer : NodeJS buffer 类型
- ObjectID : 主键,一种特殊而且非常重要的类型
- Mixed :混合类型
- Array :集合类型
- schema :用来定义表的模版,实现和MongoDB数据库的映射。用来实现每个字段的类型,长度,映射的字段,不具备表的操作能力。
- model :具备某张表操作能力的一个集合,是mongoose的核心能力。我们说的模型就是这个Mondel。
- entity :类似记录,由Model创建的实体,也具有影响数据库的操作能力。
# 数据库配置
//init.js
const mongoose = require('mongoose')
const db = "mongodb://localhost/smile-db"
const glob = require('glob');
const {resolve} = require('path');
exports.initSchemas = () =>{
glob.sync(resolve(__dirname,'./schema/','**/*.js')).forEach(require)
}
exports.connect = ()=>{
//连接数据库
mongoose.connect(db)
let maxConnectTimes = 0
return new Promise((resolve,reject)=>{
//把所有连接放到这里
//增加数据库监听事件
mongoose.connection.on('disconnected',()=>{
console.log('***********数据库断开***********')
if(maxConnectTimes<3){
maxConnectTimes++;
mongoose.connect(db)
}else{
reject()
throw new Error('数据库出现问题,程序无法搞定,请人为修理......')
}
})
mongoose.connection.on('error',err=>{
console.log('***********数据库错误***********')
if(maxConnectTimes<3){
maxConnectTimes++
mongoose.connect(db)
}else{
reject(err)
throw new Error('数据库出现问题,程序无法搞定,请人为修理......')
}
})
//链接打开的时
mongoose.connection.once('open',()=>{
console.log('MongoDB connected successfully')
resolve()
})
})
}
- 新版本增加{useNewUrlParser:true},兼容以后的版本
mongoose.connect(db,{useNewUrlParser:true},()=>{
console.log("连接成功")
})
# 创建一个schema
//User.js
const mongoose = require('mongoose') //引入Mongoose
const Schema = mongoose.Schema //声明Schema
let ObjectId = Schema.Types.ObjectId //声明Object类型
//创建我们的用户Schema
const userSchema = new Schema({
UserId:ObjectId,
userName:{unique:true,type:String},
password:String,
createAt:{type:Date,default:Date.now()},
lastLoginAt:{type:Date,default:Date.now(),
//gender: { type: String, enum: ['male', 'female'], default: 'male', required: true },
//ref表示引用,引用了Tpoic中的ObjectId
//business: { type: Schema.Types.ObjectId, ref: 'Topic', select: false },
//employments: {
// type: [{
// company: { type: Schema.Types.ObjectId, ref: 'Topic' },
// job: { type: Schema.Types.ObjectId, ref: 'Topic' },
// }],
// select: false,
//},
//ceshi:{type:String,select:false}
}
})
//发布模型
mongoose.model('User',userSchema)
String等字段相当于Schema中的关键字,不需要再加引号 如果某个字段不想要直接返回给客户端,可以添加字段select:false,如上ceshi,也可以在mongoose语法请求数据库时设置如下 可枚举性和数组模式的写法,如上注释部分
const User = mongoose.model('User')
//展示password字段
User.find().select("+password")
//隐藏password字段
User.find().select("-password")
//根据前台传过来的参数具体展示某些信息
const selectFields = fields.split(';').filter(f => f).map(f => ' +' + f).join('');
//populate,如果字段是用ref引用的,可以使用populate处理信息
const user = await User.findById(ctx.params.id).select(selectFields).populate(populateStr);
# 路由使用到schema
//index.js
const Router = require('koa-router')
const mongoose = require('mongoose')
let router = new Router()
router.get('/',async(ctx)=>{
ctx.body="这是用户操作首页"
})
router.post('/register',async(ctx)=>{
const User = mongoose.model('User')
let newUser = new User(ctx.request.body)
await newUser.save().then(()=>{
ctx.body={
code:200,
message:'注册成功'
}
}).catch(error=>{
ctx.body={
code:500,
message:error
}
})
})
router.post('/login',async(ctx)=>{
let loginUser = ctx.request.body
console.log(loginUser)
let userName = loginUser.userName
let password = loginUser.password
//引入User的model
const User = mongoose.model('User')
await User.findOne({userName:userName}).exec().then(async(result)=>{
console.log(result)
if(result){
let newUser = new User()
await newUser.comparePassword(password,result.password)
.then(isMatch=>{
ctx.body={code:200,message:isMatch}
})
.catch(error=>{
console.log(error)
ctx.body={code:500,message:error}
})
}else{
ctx.body={code:200,message:'用户名不存在'}
}
}).catch(error=>{
console.log(error)
ctx.body={code:500,message:error}
})
})
module.exports =router
# mongoose分页 模糊搜索
async find(ctx) {
const { per_page = 10 } = ctx.query;
const page = Math.max(ctx.query.page * 1, 1) - 1;
const perPage = Math.max(per_page * 1, 1);
//借助正则就可以实现 模糊搜索
ctx.body = await Topic
.find({ name: new RegExp(ctx.query.q) })
.limit(perPage).skip(page * perPage);
}
//模糊搜索多个字段
async find(ctx) {
const { per_page = 10 } = ctx.query;
const page = Math.max(ctx.query.page * 1, 1) - 1;
const perPage = Math.max(per_page * 1, 1);
const q = new RegExp(ctx.query.q);
ctx.body = await Question
.find({ $or: [{ title: q }, { description: q }] })
.limit(perPage).skip(page * perPage);
}
# index
const Koa = require('koa')
const app = new Koa()
const { connect , initSchemas } = require('./database/init.js')
const mongoose = require('mongoose')
const bodyParser = require('koa-bodyparser')
const cors = require('koa2-cors')
const Router = require('koa-router')
app.use(bodyParser())
app.use(cors())
let user = require('./appApi/user.js')
let home = require('./appApi/home.js')
let goods = require('./appApi/goods.js')
//装载所有子路由
let router = new Router()
router.use('/user',user.routes())
router.use('/home',home.routes())
router.use('/goods',goods.routes())
//egg.js
//加载路由中间件
app.use(router.routes())
app.use(router.allowedMethods())
;(async ()=>{
await connect()
initSchemas()
})()
app.use(async(ctx)=>{
ctx.body='<h1>Hello Koa2</h1>'
})
app.listen(3000,()=>{
console.log('[Server] starting at port 3000')
})
# 数据库加密
cnpm install --save bcrypt
# koa2-cors
npm install --save koa2-cors