九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
4 Koa實戰(zhàn) - Restful API

課程目標(biāo)

  • 編寫RESTful API
  • 文件上傳
  • 表單校驗
  • 圖形驗證碼
  • 發(fā)送短信
  • 案例:用戶注冊
  1. 掌握Koa中編寫Restful風(fēng)格API
  2. 掌握Koa中文件上傳、表單驗證、圖形驗證碼、發(fā)送短信等常見任務(wù)

編寫RESTful API

  • 方法設(shè)計 PUT和DELETE ngnix可能會有問題

    • GET:讀?。≧ead)
    • POST:新建(Create)
    • PUT:更新(Update)
    • PATCH:更新(Update),部分更新
    • DELETE:刪除(Delete)
  • 對象

    • GET /users(通常用復(fù)數(shù)避免多級)
    • GET /users/1 (一樣是使用復(fù)數(shù))
  • 狀態(tài)碼

    • 1xx :相關(guān)信息
    • 2xx :操作成功
    • 3xx :重定向
    • 4xx :客戶端錯誤
    • 5xx :服務(wù)器錯誤
  • 返回

        //推薦    HTTP/1.1 400 Bad Request    Content-Type: application/json    {     "error": "不合法的附件",     "detail": { "uname": "用戶名為必填項" }    }
  • 解決跨域: npm i koa2-cors

    var Koa = require('koa');var cors = require('koa2-cors');var app = new Koa();app.use(cors());

    參考文檔:理解resful架構(gòu)、 resful API最佳實踐

文件上傳

  • 安裝koa-multer: npm i koa-multer -S
  • 配置:./routes/users.js

    const upload = require("koa-multer")({ dest: "./public/images" });router.post("/upload", upload.single("file"), ctx => { console.log(ctx.req.file); // 注意數(shù)據(jù)存儲在原始請求中 console.log(ctx.req.body); // 注意數(shù)據(jù)存儲在原始請求中 ctx.body = "上傳成功";});
  • 調(diào)用接口,./public/upload-avatar.html

    <!DOCTYPE html><html lang="en"> <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <meta http-equiv="X-UA-Compatible" content="ie=edge" />  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  <script src="https://unpkg.com/element-ui/lib/index.js"></script>  <link   rel="stylesheet"     />  <style>   .avatar-uploader .el-upload {    border: 1px dashed #d9d9d9;    border-radius: 6px;    cursor: pointer;    position: relative;    overflow: hidden;  }   .avatar-uploader .el-upload:hover {    border-color: #409eff;  }  .avatar-uploader-icon {    font-size: 28px;    color: #8c939d;    width: 178px;    height: 178px;    line-height: 178px;    text-align: center;  }   .avatar {    width: 178px;    height: 178px;    display: block;  }  </style>  <title>文件上傳</title> </head> <body>  <div id="app">   <!-- ajax方式上傳 -->   <el-upload    class="avatar-uploader"    action="/users/upload"    :show-file-list="false"    :on-success="handleAvatarSuccess"    :before-upload="beforeAvatarUpload"   >    <img v-if="imageUrl" :src="imageUrl" class="avatar" />    <i v-else class="el-icon-plus avatar-uploader-icon"></i>   </el-upload>  </div>  <script>   var app = new Vue({    el: "#app",    data() {     return {      imageUrl: ""    };   },    methods: {     handleAvatarSuccess(res, file) {      this.$message.success('上傳頭像成功')      this.imageUrl = URL.createObjectURL(file.raw);    },     beforeAvatarUpload(file) {      const isJPG = file.type === "image/jpeg";      const isLt2M = file.size / 1024 / 1024 < 2;      if (!isJPG) {       this.$message.error("上傳頭像圖片只能是 JPG 格式!");     }      if (!isLt2M) {       this.$message.error("上傳頭像圖片大小不能超過 2MB!");     }      return isJPG && isLt2M;    }   }  });  </script> </body></html>

表單校驗

  • 安裝koa-bouncer: npm i -S koa-bouncer
  • 配置:app.js

    // 為koa上下文擴展一些校驗方法app.use(bouncer.middleware());
  • 基本使用:user.js

    router.post("/", ctx => { try {  // 校驗開始  ctx  .validateBody("uname")  .required("要求提供用戶名")  .isString()  .trim()  .isLength(6, 16, "用戶名長度為6~16位");  // ctx.validateBody('email')  // ?.optional()  // ?.isString()  // ?.trim()  // ?.isEmail('非法的郵箱格式')  ctx  .validateBody("pwd1")  .required("密碼為必填項")  .isString()  .isLength(6, 16, "密碼必須為6~16位字符");  ctx  .validateBody("pwd2")  .required("密碼確認(rèn)為必填項")  .isString()  .eq(ctx.vals.pwd1, "兩次密碼不一致");  // 校驗數(shù)據(jù)庫是否存在相同值  // ctx.validateBody('uname')  // ?.check(await db.findUserByUname(ctx.vals.uname), 'Username taken')  ctx.validateBody("uname").check("jerry", "用戶名已存在");  // 如果走到這里校驗通過  // 校驗器會用凈化后的值填充 `ctx.vals` 對象  console.log(ctx.vals);  console.log("POST /users");  // const { body: user } = ctx.request; // 請求body  const user = ctx.vals;  user.id = users.length + 1;  users.push(user);  ctx.body = { ok: 1 };} catch (error) {  if (error instanceof bouncer.ValidationError) {   ctx.body = '校驗失?。?+error.message;   return; }  throw error}});

圖形驗證碼(就為了拿個圖片?)

  • 安裝trek-captcha: npm i trek-captcha -S
  • 使用:./routes/api.js

    const captcha = require("trek-captcha");router.get("/captcha", async ctx => { const { token, buffer } = await captcha({ size: 4 }); ctx.body = buffer;});
  • 圖片顯示,upload-avatar.html

    <!-- 驗證碼 --><img src="/api/captcha" id="captcha" /><script>document.getElementById('captcha').onclick = function() {   captcha.src = "/users/captcha?r=" + Date.now(); };</script>

    發(fā)送短信

  • 秒滴短信API
  • 安裝依賴: npm i -S moment md5 axios
  • 接口編寫,./routes/api.js

    router.get("/sms", async function(ctx) { // 生成6位隨機數(shù)字驗證碼 let code = ran(6); // 構(gòu)造參數(shù) const to = ctx.query.to; // 目標(biāo)手機號碼 const accountSid = "3324eab4c1cd456e8cc7246176def24f"; // 賬號id const authToken = "b1c4983e2d8e45b9806aeb0a634d79b1"; // 令牌 const templateid = "613227680"; // 短信內(nèi)容模板id const param = `${code},1`; // 短信參數(shù) const timestamp = moment().format("YYYYMMDDHHmmss"); const sig = md5(accountSid + authToken + timestamp); // 簽名 try {  // 發(fā)送post請求  const resp = await axios.post(   "https://api.miaodiyun.com/20150822/industrySMS/sendSMS",   qs.stringify({ to, accountSid, timestamp, sig, templateid, param }),  { headers: { "Content-Type": "application/x-www-form-urlencoded" } } );  if (resp.data.respCode === "00000") {   // 短信發(fā)送成功,存儲驗證碼到session,過期時間1分鐘   const expires = moment()   .add(1, "minutes")   .toDate();   ctx.session.smsCode = { to, code, expires };   ctx.body = {ok:1} } else {    ctx.body = {ok:0, message: resp.data.respDesc} }} catch (e) {  ctx.body = {ok:0, message: e.message}}});

案例:用戶注冊

  • 前端頁面,register.html

    <!DOCTYPE html><html lang="en"> <head>  <meta charset="UTF-8" />  <meta name="viewport" content="width=device-width, initial-scale=1.0" />  <meta http-equiv="X-UA-Compatible" content="ie=edge" />  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  <script src="https://unpkg.com/element-ui/lib/index.js"></script>  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>  <link rel="stylesheet" />  <style></style>  <title>文件上傳</title> </head> <body>  <div id="app">   <el-form :model="regForm" ref="regForm">    <el-form-item>     <el-input      type="tel"      v-model="regForm.phone"      autocomplete="off"      placeholder="手機號"     ></el-input>    </el-form-item>    <el-form-item>     <el-input      type="text"      v-model="regForm.captcha"      autocomplete="off"      placeholder="圖形驗證碼"     ></el-input>     <img :src="captchaSrc" @click="getCaptcha" />    </el-form-item>    <el-form-item>     <el-input      type="text"      v-model="regForm.code"      autocomplete="off"      placeholder="短信驗證碼"     ></el-input>     <el-button type="primary" @click="getSmsCode()"      >獲取短信驗證碼</el-button     >    </el-form-item>    <el-form-item>     <el-input      type="password"      v-model="regForm.password"      autocomplete="off"     ></el-input>    </el-form-item>    <el-form-item>     <el-button type="primary" @click="submitForm()">提交</el-button>    </el-form-item>   </el-form>  </div>  <script>   var app = new Vue({    el: "#app",    data() {     return {      regForm: {       phone: "",       captcha: "",       code: "",       password: ""     },      captchaSrc: "/api/captcha"    };   },    methods: {     getCaptcha() {      this.captchaSrc = "/api/captcha?r=" + Date.now();    },     getSmsCode() {      axios      .get("/api/sms?to=" + this.regForm.phone)      .then(res => res.data)      .then(({ code }) => (this.regForm.code = code));    },     submitForm() {      axios      .post("/students", this.regForm)      .then(() => alert("注冊成功"))      .catch(error => alert("注冊失敗:" + error.response.data.message));    }   }  });  </script> </body></html>
  • 注冊接口編寫,./routes/students.js
const Router = require("koa-router");const router = new Router({ prefix: "/students" });const bouncer = require("koa-bouncer");router.post("/", async ctx => {?try {??// 輸入驗證??const { code, to, expires } = ctx.session.smsCode;??ctx??.validateBody("phone")??.required("必須提供手機號")??.isString()??.trim()??.match(/1[3-9]\d{9}/, "手機號不合法")??.eq(to, "請?zhí)顚懡邮斩绦诺氖謾C號");??ctx??.validateBody("code")??.required("必須提供短信驗證碼")??.isString()??.trim()??.isLength(6, 6, "必須是6位驗證碼")??.eq(code, "驗證碼填寫有誤")??.checkPred(() => new Date() - new Date(expires) < 0, "驗證碼已過期");??ctx??.validateBody("password")??.required("必須提供密碼")??.isString()??.trim()??.match(/[a-zA-Z0-9]{6,16}/, "密碼不合法");??// 入庫, 略??ctx.body = { ok: 1 };} catch (error) {??if (error instanceof bouncer.ValidationError) {???console.log(error);???ctx.status = 401;?} else {???ctx.status = 500;?}??ctx.body = { ok: 0, message: error.message };}});module.exports = router;

koa2 中間件

  • 路由相關(guān)

    • 'koa-bodyparser' 【post解析】

      app.use(bodyParser({    extendTypes:\['json','form','text'\]  }))
    • 'koa-router' 【路由】

      import Router from 'koa-router';  import axios from './utils/axios'  import Cart from '../dbs/models/cart'  import md5 from 'crypto-js/md5' //加密  let router \= new Router({prefix: '/cart'})  router.post('/getCart', async ctx \=> {    let {id} \= ctx.request.body    console.log(id);    try {      let result \= await Cart.findOne({cartNo: id})      ctx.body \= {        code: 0,        data: result          ? result.detail\[0\]          : {}      }    } catch (e) {      ctx.body \= {        code: -1,        data: {}      }    }  })
    • 'koa-multer' 【文件上傳】

      router.post("/upload", upload.single("file"), ctx \=> {    console.log(ctx.req.file); // 注意數(shù)據(jù)存儲在原始請求中    console.log(ctx.req.body); // 注意數(shù)據(jù)存儲在原始請求中    ctx.body \= "上傳成功";  });
    • 'koa2-cors' 【跨域】

      // 跨域  var cors \= require('koa2-cors');  app.use(cors());
    • 'koa-bouncer' 【校驗】

      //配置const bouncer \= require("koa-bouncer");  app.use(bouncer.middleware());//使用router.post("/", ctx => { try {  // 校驗開始  ctx  .validateBody("uname")  .required("要求提供用戶名")  .isString()  .trim()  .isLength(6, 16, "用戶名長度為6~16位");  // ctx.validateBody('email')  // ?.optional()  // ?.isString()  // ?.trim()  // ?.isEmail('非法的郵箱格式')  ctx  .validateBody("pwd1")  .required("密碼為必填項")  .isString()  .isLength(6, 16, "密碼必須為6~16位字符");  ctx  .validateBody("pwd2")  .required("密碼確認(rèn)為必填項")  .isString()  .eq(ctx.vals.pwd1, "兩次密碼不一致");  // 校驗數(shù)據(jù)庫是否存在相同值  // ctx.validateBody('uname')  // ?.check(await db.findUserByUname(ctx.vals.uname), 'Username taken')  ctx.validateBody("uname").check("jerry", "用戶名已存在");  // 如果走到這里校驗通過  // 校驗器會用凈化后的值填充 `ctx.vals` 對象  console.log(ctx.vals);  console.log("POST /users");  // const { body: user } = ctx.request; // 請求body  const user = ctx.vals;  user.id = users.length + 1;  users.push(user);  ctx.body = { ok: 1 };} catch (error) {  if (error instanceof bouncer.ValidationError) {   ctx.body = '校驗失?。?+error.message;   return; }  throw error}});
  • 數(shù)據(jù)庫相關(guān)

    • 'koa-generic-session' 【登錄狀態(tài)鑒權(quán)】

      app.use(session({key: 'mt', prefix: 'mt:uid', store: new Redis()}))
    • 'koa-session' 【登錄狀態(tài)鑒權(quán)】

      app.keys \= \['some secret'\];  //設(shè)置秘鑰// 配置項  const SESS\_CONFIG \= {      key: 'kkb:sess', // cookie鍵名    maxAge: 86400000, // 有效期,默認(rèn)一天    httpOnly: true, // 僅服務(wù)器修改    signed: true, // 簽名cookie  };// 注冊  ~~~~app.use(session(SESS\_CONFIG, app));
    • 'koa-redis' 【redis】

      app.use(session({key: 'mt', prefix: 'mt:uid', store: new Redis()}))
    • 'mongoose' 【面向?qū)ο蟛僮鲾?shù)據(jù)庫】

      //連接mongoose.connect(dbConfig.dbs,{    useCreateIndex: true,    useNewUrlParser:true  })//操作import mongoose from 'mongoose'  const Schema \= mongoose.Schema  const Cart \= new Schema({    id: {      type: String,      require: true    },    detail: {      type: Array,      require: true    },    cartNo: {      type: String,      require: true    },    user: {      type: String,      require: true    },    time: {      type: String,      require: true    }  })  export default mongoose.model('Cart', Cart)
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
5分鐘教你用nodeJS手寫一個mock數(shù)據(jù)服務(wù)器
在Sequelize中使用遷移
GraphQL入門有這一篇就足夠了
vue koa2 mongodb 從零開始做個人博客(二) 登錄注冊功能后端部分
5 基于Koa的egg.js企業(yè)級后端框架使用
文件下載,搞懂這9種場景就夠了
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服