Koa进阶

作者: hellomyshadow | 来源:发表于2019-04-21 10:41 被阅读0次

    Koa脚手架

    1. 全局安装脚手架:npm install koa-generator -g
    2. 创建项目:koa demo01  --> cd demo01  --> npm install
    3. 运行项目:npm start
    4. 脚手架创建的项目已经实现了路由的模块化,即项目的模块化。
    

    路由模块化

    1. 与Express的路由模块化类似,把不同功能的路由拆分到不同的js文件中,然后再暴露路由对象;
    2. 假设项目包含首页(index)、后台管理(admin),配置模板引擎art-template的目录为views
        1. 在根目录下创建routes目录,用于存放路由模块,项目入口为app.js
        2. 创建routes/index.js,routes/admin.js
    3. 在index.js中配置index模块的路由,index是根路由的模块
        let router = require('koa-router')();
        router.use(async(ctx, next)=>{ ----> index模块的应用级中间件,在index路由之前匹配
            ......
            await next(); ----> 继续向下匹配index路由
            ......
        })
        router.get('/', async(ctx)=>{
            await ctx.render('index'); -->渲染模板:views/index.html
        })
        router.get('case', async(ctx)=>{  ------> 对于根路由的模块,其子路由不能再加'/'
            await ctx.render('index/case'); -->渲染模板:views/index/case.html
        })
        module.exports = router; ---> 暴露index模块的路由对象
        1. 注意:与Express不同,Koa的根目录匹配已经默认加了'/',其子路由的开头不能再加'/'
    4. 在admin.js中配置admin模块的路由
        let router = require('koa-router')();
        router.use(async(ctx, next)=>{ ----> admin模块的应用级中间件,在admin路由之前匹配
            ......
            await next(); ----> 继续向下匹配admin路由
            ......
        })
        router.get('/', async(ctx)=>{
            await ctx.render('admin');
        })
        router.get('/user', async(ctx)=>{
            await ctx.render(admin/user');
        })
        module.exports = router;
    5. 在app.js中启用index模块和admin模块的路由
        let router = require('koa-router')();
        let index = require('./routes/index');
        let admin = require('./routes/admin');
        router.use('/', index.routes());  -----> 启用根路由的index模块
        router.use('/admin', admin.routes()); ---> admin模块的路由
        app.use(router.routes()).use(router.allowedMethods);
    6. 子路由:在admin路由中继续启用子路由
        1. 创建routes/admin/user.js,配置路由
        let router = require('koa-router')();
        router.get('/', async(ctx)=>{
            await ctx.render('admin/user'); -->渲染模板:views/admin/user.html
        })
        router.get('/add', async(ctx)=>{
            await ctx.render('admin/user/add'); ->渲染模板:views/admin/user/add.html
        })
        module.exports = router;
        2. 在admin.js中引入user.js,并启用user路由
        let user = require('./admin/user');
        router.use('/user', user.routes());
    7. router路由的写法不止一种,比如把路由写在对应的路由文件中
        1. app.js:router.use(admin.routes());
        2. admin.js:let Router = require('koa-router');
        let router = new Router({ prefix: '/admin' })
    

    更多补充

    1. nodeJs生成验证码:svgCaptcha,支持express和koa
    2. 页面自动刷新/跳转
        1. 页面3s后自动刷新:<meta http-equiv="refresh" content="3" />
        2. 3s后页面自动转到指定网址
        <meta http-equiv="refresh" content="3; url=http://www.baidu.com/" />
        3. 登录失败之后,加载错误页面error.html,5s后自动转回登录页
        router.use(async(ctx, next)=>{
            ctx.state.HOST = 'http://'+ctx.request.header.host;  -->设置域名的全局变量
            await next();
        })
        router.post('doLogin', async(ctx)=>{
            if(登录失败){
                await ctx.render('login/error', { url: ctx.state.HOST+'/login' })
            }
        })
        error.html:<meta http-equiv="refresh" content="5; url={{url}}" />
    3. art-template自定义日期管道/过滤器
        1. 格式化日期的插件:npm install silly-datetime --save
        2. let sd = require('silly-datetime');
        render(app, {
            root: path.join(__dirname, 'views'),
            extname: '.html',
            debug: process.env.NODE_ENV !== 'production',
            dateFormat: dateFormat=function(value){ -----> 扩展模板里的方法
                return sd.format(new Date(value), 'YYYY-MM-DD HH:mm');
            }
        })
        3. 在art模板中使用过滤器,格式化传递的变量time:<div>{{time | dateFormat}}</div>
    4. koa-jsonp:ajax请求返回JSON的中间件,npm install koa-jsonp --save
        1. let jsonp = require('koa-jsonp');  ---> 同时支持处理JSON和jsonp
        2. 配置jsonp中间件:app.use(jsonp());
        3. 一个简单的JSON数据接口:
        router.get('/getMsg', async (ctx) => {
            ctx.body = { message: "请求的数据信息", success: true }
        })
        4. 使用浏览器测试接口:
        http://localhost:3000/getMsg  ---> 如果返回JSON格式的数据,则表示此接口支持JSON
        http://localhost:3000/getMsg?callback=xxx  ---> 测试接口是否支持jsonp
    5. ctx.request.headers['referer']:获取上一页的地址
        1. 用全局变量记录上一页的地址
        ctx.state.prevPage = ctx.request.headers['referer'];
        2. 返回上一页:ctx.redirect(ctx.state.prevPage);
    

    文件上传

    <form action="{{HOST}}/doUpload" method="post" enctype="multipart/form-data">
        <input type="file" id="pic" name="pic" />
    </form>
    1. koa-multer:用于处理 multipart/form-data 类型的表单数据,主要用于上传文件;
    2. koa-multer基于 multer 模块:npm i koa-multer --save
        let multer = require('koa-multer');
        let storage = multer.diskStorage({
            destination: function(req, file, cb) {
                cb(null, 'upload/pic'); ---> 配置上传文件的目录:当前目录下的upload/pic
            },
            filename: function(req, file, cb) {
                let extname = (file.originalname).split('.');  -->从文件名中切割出后缀名
                cb(null, Date.now()+'.'+extname[extname.length-1]); -->对文件重命名
            }
        });
        let upload = multer({storage: storage});
    3. 处理上传文件
        router.post('/doUpload', upload.single('pic'), async (ctx)=>{
            let filename = ctx.req.file.filename;  ---> 上传的文件名
            let form = ctx.req.body; ---> form表单的其他数据
        })
    4. upload.single('pic'):pic与<input type="file" name="pic" />的name保持一致;
    5. koa-multer也支持多个文件上传,在github上的multer模块中有更多配置信息;
    6. koa-body:用于取代 koa-bodyparser 和 koa-multer
    

    路由鉴权

    1. koa-jwt:用于路由鉴权、token验证
    

    富文本编辑器

    1. ueditor:百度的轻量级、可定制富文本web编辑器,开源基于MIT协议,允许自由使用和修改代码
    2. ueditor官方虽然没有提供NodeJs版本,但官方推荐的第三方插件里有nodeJs版本;
        1. 第三方插件直接支持express,不支持koa2
        2. 支持koa2的ueditor插件:npm i koa2-ueditor --save
    3. ueditor的基本配置
        1. 在github下载koa2-ueditor的demo,拷贝public/ueditor,粘贴到自己项目的public目录
        2. 在模板中的<head>标签中引入ueditor目录下的静态文件
        <script type="text/javascript" src="/ueditor/ueditor.config.js">
        <script type="text/javascript" src="/ueditor/ueditor.all.min.js">
        <script type="text/javascript" src="/ueditor/lang/zh-cn/zh-ch.js">
        3. 使用ueditor,取代<textarea>的位置
        <script id="editor1" type="text/plain" style="width:800px;height:300px;">
        4. 在<body>标签之后实例化富文本编辑器:
        <script type="text/javascript">
            let ue = UE.getEditor('editor1');
        </script>
        5. 富文本编辑器中的内容最终生成的是带有style样式的html标签,是一个html字符串。
        <form ...>
            <script type="text/plain" id="editor1" name="content" style="...">
        </form>
        router.post('/doUpload', upload.single('pic'), async (ctx)=>{
            let content = ctx.req.body.content; ---> form表单的富文本编辑框中的数据
        })
    4. 配置ueditor的图片上传
        const ueditor = require('koa2-ueditor');
        router.all('/editor/controller', ueditor(['public', {
            imageAllowFiles: ['.png', '.jpg', '.jpeg'],
            imagePathFormat: '/upload/ueditor/image/{yyyy}{mm}{dd}/{filename}'
        }]));
        1. '/editor/controller':统一上传的地址,对应ueditor/ueditor.config.js中的配置
        serverUrl: "/editor/controller"  ---> 根据router.all()的实际路由进行修改
        http://localhost:3000/editor/controller  --> 完整的上传地址URI
        2. 'public':上传图片的保存目录,根目录/public/upload/ueditor/image/当前日期/图片名
    5. 自定义ueditor编辑框:修改配置文件ueditor/ueditor.config.js
        1. 配置自动增长高度:autoHeightEnabled: false  --> 编辑框的内容过长时自动出现滚动条
        2. 自定义工具栏:修改toolbars节点
    6. 为编辑框设置默认内容
        <script type="text/javascript">
            let ue = UE.getEditor('editor1');
            ue.addListener('ready', ()=>{  ----> 监听ueditor准备完成
                ue.setContent(`{{@list.content}}`);  --> art-template模板接收参数的方式
            })  ---> list.content是上一次富文本编辑框中的内容,保存在数据库中
        </script>
    

    SEO优化

    1. SEO优化:也称为搜索引擎优化,目的是让搜索引擎优先搜索到自家网站,并展示给用户;
    2. 设置网站的必要信息:标题、关键字、描述
        1. 网站标题:<title>标题内容</title>,网站标题变化不能过于频繁,否则百度会认为是作弊;
        2. 网站关键字:<meta name="Keywords" content="关键字内容" />
        3. 网站描述:<meta name="Description" content="描述内容" />
    3. 图片<img>必须使用 alt 属性
    4. html标签的合理使用,语义化,符合W3C标准
        1. 尤其是 h 系列标签的合理使用,其中,<h1>标签的权重最高,一个页面建议只出现一次;
        2. <h1>标签的内容建议和<title>的内容相同。
    5. 内链、外链的合理使用,如友情链接就属于外链,因为搜索引擎会根据内链和外链继续搜索网站;
    6. 网站的内容尽量都是原创的;
    7. 合理使用长尾关键词:比如,相对与"koa2教程","koa2视频教程"就属于长尾关键词.
    

    API接口

    1. NodeJs的异步环境特性,让它最适合写API接口,非常善于处理大数据、高并发;
    2. 比如一个返回JSON数据的简单接口
        let jsonp = require('koa-jsonp');
        app.use(jsonp());
        router.get('/getList', async (ctx)=>{
            let result = await (从数据库中获取数据);
            ctx.body = { data: result }
        })
    

    跨域问题

    1. 在AJAX请求后台接口数据时,浏览器的同源策略会引起跨域安全问题;
        1. 接口的协议、域名、端口号必须与当前Web应用所处的协议、域名、端口号保持一致;
        2. 比如,访问当前网页的地址为 http://localhost:3000/index,那么,网页中的AJAX请求的
        接口地址必须是http://localhost:3000/xxxx
        3. 协议、域名、端口号三者有任何一个出现不一致,就会导致跨域问题。
    2. JSONP的原理:利用<script>可以跨域的特性
        1. 在本地写一个回调函数,在远程执行这个函数,并把远程数据传到本地
        http://localhost:3000/api/getList?callback=xxx ---> xxx被当作远程执行的函数
        2. JSONP跨域请求的前提:服务器必须支持JSONP;第三方koa-jsonp模块同时支持JSONP请求。
    3. 除了JSONP实现跨域请求,还可以让后台设置允许跨域:npm i koa2-cors --save
        1. NodeJs后台设置允许跨域请求
        let cors = require('koa2-cors');
        app.use(cors());
        2. AJAX可以直接跨域请求接口,但由此导致的安全性问题,则通过token验证解决。
    

    RESTful API

    1. 当前Web应用的趋势就是前后端分离,为了让前端设备与后端更好地通信,出现了很多API结构;
    2. RESTful API是目前比较成熟的一套互联网应用程序的API设计理念;
    3. 一个优秀的RESTful API所考虑的方面:
        1. 协议:建议使用更安全的https协议
        2. 域名:尽量部署在专属域名下面,如https://a.bcd.com,https://api.bcd.com
        3. 考虑到接口的升级,应该将API的版本号放在URI中
        https://a.bcd.com/api1/list,https://a.bcd.com/api2/list
        https://a1.bcd.com,https://a2.bcd.com
        4. 路径:在RESTful架构中,每个URI代表一种资源,所以URI中使用与数据库表名相对应的名词
        5. 使用合理的HTTP请求方法
    4. HTTP的7种请求方法:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS,常用的只有前4种
        1. GET:select,从服务器取出一项或多项资源
        2. POST:create,在服务器新建一个资源
        3. PUT:update,在服务器更新/修改资源
        router.put('/edit', async (ctx)=>{  ---> koa2可以直接识别不同的请求方法
            //修改数据、并返回修改后的完整数据
        })
        4. DELETE:从服务器删除资源
        router.delete('/del', async (ctx)=>{ ---> 响应 delete 方式的请求
            //删除数据
        })
    5. 以vueJs的axios为例,axios提供了7种不同的HTTP请求方法。
    

    发布线上

    1. 购买域名和服务器:万网(阿里收购)、西部数码...
    2. 域名备案:新购买的域名不能直接被解析到服务器,需要在管理局登记域名信息(20个工作日左右)
        1. 每个出售域名的网站上,会有域名备案的流程说明和入口;
        2. 当然,还可以出钱到就近的外包公司备案。
    3. 域名解析:让域名和服务器IP地址相关联,在购买域名的网站上配置即可;
        1. DNS服务器:负责域名解析的服务器,返回真实的服务器IP地址;
        2. ping 域名:查看当前域名所指向的真实服务器IP,如果ping失败,可能此域名设置了拒绝。
        ping www.baidu.com
    4. nginx:负责转发与负载均衡,从而可以在一台服务器上运行N个nodeJs应用程序。
    

    nginx配置

    1. 在当前服务器上有2个nodeJs应用程序,端口号分别为8001、8002
    2. 下载nginx应用包,解压,改名为nginx
    3. 配置nginx/conf/nginx.conf
        1. 配置http节点:转发规则
        http {
            upstream backaa {
                server 127.0.0.1:8001; ---> 服务器上的nodeJs应用程序的端口号
            }
            upstream backbb {
                server 127.0.0.1:8002;
            }
        }
        2. 配置http节点下的server节点:反向代理/负载均衡
        server {
            listen       80;
            server_name  aa.v123.com;  ---> 域名
    
            #location / {
            #   root   html;
            #   index  index.html index.htm;
            #}
    
            location / {
                # 设置主机头和客户端的真实地址,以便服务器获取客户端的真实IP
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                #禁用缓存
                proxy_buffering off;
                #反向代理的地址
                proxy_pass http://backaa;  ---> 与upstream相对应
            }
            ......
        }
        server {
            listen       8080;
            server_name  bb.v123.com;  ---> 域名
            
            #location / {
            #   root   html;
            #   index  index.html index.htm;
            #}
    
            location / {
                # 设置主机头和客户端的真实地址,以便服务器获取客户端的真实IP
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                #禁用缓存
                proxy_buffering off;
                #反向代理的地址
                proxy_pass http://backbb;  ---> 与upstream相对应
            }
            ......
        }
    5. 启动nginx(windows系统):双击运行nginx/nginx.exe
    6. 启动nodeJs应用程序
    7. 访问:http://aa.v123.com,http://bb.v123.com
    

    相关文章

      网友评论

          本文标题:Koa进阶

          本文链接:https://www.haomeiwen.com/subject/bpudgqtx.html