• node基础及express、koa框架


    1.1 为什么学习Node?

    IO优势:对于文件读写,Node采用的是非阻塞IO;传统IO在读写文件的时候CPU来处理,而代码执行也处于等待中,浪费性能;非阻塞IO将读写操作交给CPU,而代码正常执行,减少等待浪费的性能__

    应用场景:实际应用: webpack/gulp/npm/http-server/json-server;服务器中负责IO读写的中间层服务器(天猫中间层IO服务器)

    1.2 NodeJS特点

    其移植了chrome V8 引擎,解析和执行代码机制和浏览器js相同;其沿用了JavaScript语法、另外扩展了自己需要的功能;总结: nodejs 是一个后端语言 , 其具备操作文件的能力, 可以具备服务器的创建和操作能力(其语法是JavaScript语法,代码运行在chrome V8 引擎之上)

    二、内置对象介绍

    分类

    • 全局对象: 何时何处都能访问
    • 核心对象: 向系统索要,引入即可使用
    • 自定义对象: 按路径引入即可

    2.1 全局对象

    2.1.1 process(全局对象)

    • 每个系统的环境变量几乎都不一样,可以利用环境变量中的具体某个特定的值来区分不同的机器
    • process.env 是一个对象,我们可以通过其.属性名来获取具体的环境变量值
      • 设置一个特定的环境变量,以达到简单区分不同的机器,从而针对生产/开发环境运行不同的效果
    • process.argv 获取命令行参数

    2.1.2 filename/dirname(全局对象)

    • __filename 获取当前运行文件的目录,绝对路径
    • __dirname 当前运行文件的绝对路径

    2.1.3 nodejs实现规范

    • CommonJS : 规范JavaScript语言作为后端语言运行的标准
      • 具备什么能力,该怎么做 ,比如: 具备服务器的功能/ 可以操作文件 …
      • 模块应该怎么写: Module :
        • 1:依赖一个模块 require(‘模块名(id)’)
        • 2: 需要被模块依赖 module.exports = 给外部的数据
        • 3:一个文件是一个模块

    2.2 核心对象path

    • 1:const path = require('path');

    • 路径 -> 在处理路径的时候很擅长,但是,其不负责判断路径是否存在文件

    • 拼接并修正路径 path.join(__dirname,'a','b'); 以当前目录/a/b

    • path.resovle('./xxx') 相对转绝对

    • 接收一个合法的路径字符串,转换成一个对象

      let pathObj = path.parse(mypath);
      
    • 接收一个路径对象,转换成一个字符串路径

      let str = path.format(pathObj);
      
    { root: 'C:\',
      dir: 'C:\Users\孙悟空',
      base: '金箍棒.txt',   // 该属性可以用于修改文件名和后缀
      ext: '.txt',
      name: '金箍棒' }
    

    注意:path对象是方便我们操作路径的,对于获取来讲: parse解析成对象,format转换成字符串.join拼接并修正… 对于修改路径对象来讲,可以用base属性更改,不能用name,ext更改

    三、包(文件夹)

    • 多个文件,有效的被组织与管理的一个单位
    • 留一个入口
    • 包就是一个:文件夹

    3.1 模块弊端:

    • 在js中要涉及到逻辑,还要在html中,为逻辑对象考虑引用顺序
    • 所有对象默认都是全局对象,命名冲突
    • commonjs规范
    • 一个文件就是一个模块
      • 导入用require(’./xxx.js’);
      • 导出用module.exports = xxx;
      • 在每一个模块内声明的变量属于模块内的作用域

    3.2 npm

    • 自己先有一个包描述文件(package.json)
    • 创建一个包描述文件 npm init [-y]
      • 会根据当前的文件夹来自动生成包名(不允许中文,不允许大写英文字母)
      • 默认生成npm init [-y]
    • 下载一个包 npm install art-template jquery@1.5.1 --save
      • 记录依赖--save
    • 根据package.json文件中的dependencies属性恢复依赖
      • 恢复包 npm install 简单: npm i 包名
    • 卸载一个包 npm uninstall jquery@1.5.1 --save
      • npm un jquery@1.5.1 --S
      • 小结:以上简写: uninstall -> un ,install -> i , --save -> -S
    • 查看包的信息
      • npm info jquery
    • 查看包的信息中的某个字段(版本)
      • npm info jquery versions
    • 查看包的文档
      • npm docs jquery
    • 安装全局命令行工具
      • npm install -g http-server
    • 卸载全局命令行工具
      • npm uninstall -g http-server
    • 查看全局包的下载路径
      • npm root -g
    • 修改存储目录
      • npm config set prefix "D:xxx"
      • 不要node_modules
      • 接着,修改环境变量中的path属性
        • 添加或改为D:xxx
        • 目的就是为了在任意目录启动 xxx.cmd
      • 重启命令行

    3.3 nrm是npm的镜像源管理工具

    • 1:全局安装 npm install -g nrm
    • 2:查看当前可选的镜像源 nrm ls
    • 3:切换镜像源 nrm use taobao
    • 选修: 添加自己公司私有源 ```nrm add name http://www.xxx.xxx/

    3.4 包的加载机制

    • 我们未来可能需要辨识一个包中,入口是否是我们想要的启动程序
    • 逐级向上查找node_module,直到盘符根目录
    • 1:查找node_modules下的包名文件夹中的main属性(常用)
    • 2:不常用:查找node_modules下的包名.js
    • 3:查找node_modules下的包名文件夹中的index.js(常用)
    • 逐级向上,node_modules,要么main属性,要么index.js

    3.5 包的区别

    • 凡是我们下载到项目的node_modules中的包,基本都是拿来做require(‘xxx’) 调用其函数和属性
    • 还有一类属于工具性的包(全局命令行工具)
      • 在命令行直接使用的
    • 全局工具 和项目包的区别
      • 全局工具哪个目录都可以通过命令行启动,通过任意目录启动该工具,给相对路径传递任意目录的文件给该工具
      • 项目中的包,部分具备命令行工具的能力,需要命令行环境变量的支持

    四、模块

    4.1 fs文件模块

    • 文件读写
    • 其他功能
    • 扩展介绍

    4.1.1 操作文件对象

    • IO

      • I :input输入
      • O:output 输出
      • 文件的操作就是IO
    • 复制文件的过程, I: 通过计算机,存储文件到剪切板

      • 粘贴到指定目录: O: 通过计算机,将剪切板上的数据,写出到 指定目录
    • node中有两种IO的操作

      • 同步IO

        • 一行代码(读文件)不执行完毕…后续代码不能执行
      • 异步IO (建议)

        • 一行代码(读写文件) 不执行完毕(正在读写中) … 后续代码也可以执行
      • 代码体验:

        • 读写文件

        • const fs = require('fs'); //必须这个名称
          //读 fs.readFile(路径,回调函数);
          //写 fs.writeFile(路径,数据,回调函数);
          
        • 总结: 异步的读/写文件 参数1:都是路径,可以相对可以绝对,最后一个参数都是回调函数,回调函数的参数中错误对象优先

    • 同步和异步IO的区别: 同步IO会阻塞后续代码执行,异步IO不会阻塞后续代码执行

    • 读取文件夹,获取其中所有文件的资源

    • stat 获取文件状态

    • readdir 读取文件夹数据

    • access 判断文件或文件夹是否存在

    4.2 http核心模块

    4.2.1 http超文本传输协议

    • 协议至少双方 -> http双方!!
      • 客户端(浏览器) -> 服务器 BS
      • 原生应用(QQ) -> 服务器 CS
    • 就是数据如何传输
    • 特点:
      • 一问一答(先有请求,后有响应)
      • 5大特点:
        • 轻便/ 简单快速 支持客户/服务器模式
        • 无连接(不为每一个请求保持住链接)
        • 无状态( 服务器不记得客户端是谁 ) -> cookie

    4.2.2 请求与响应交互的过程

    • 见图

    4.2.3 主体对象

    • 服务器对象 http.createServer();
    • 客户端对象http.request({host:'www.baidu.com'});
    • 请求报文对象(对于服务器来说,是可读) req
    • 响应报文对象(对于服务器来说,是可写) res

    4.2.4 状态码分类

    • 1 开头,正在进行中
    • 2开头,完成
    • 3开头 ,重定向
    • 4开头 , 客户端异常
    • 5开头, 服务器异常

    4.2.5 创建服务器步骤

    • 1:引入http核心对象
    • 2:利用http核心对象的.createServer(callback); 创建服务器对象
    • 3:使用服务器对象.listen(端口,ip地址) 开启服务器
    • 4:callback(req,res) 根据请求处理响应

    4.2.6 请求对象

    • 请求首行中的url req.url
    • 请求首行中的请求方式 req.method
    • 请求头中的数据req.headers 是一个对象
    • 头信息中,也可以作为与服务器交互的一种途径

    4.2.7 获取请求体数据

    • 代码对比
    • 浏览器: $(’#xx’).on(‘submit’,function(e){ })
    • 服务器: req.on(‘data’,function(d){ d.toString(); })

    4.2.8 querystring核心对象

    • querystring.parse(formStr)
    • username=jack&password=123转换成如下
    • { username: ‘jack’, password: ‘123’ }

    4.2.9 响应对象

    • 响应首行 res.writeHead(状态码)
    • 写响应头
      • 一次性写回头信息:res.writeHead(200,headers)`
      • 多次设置头信息:res.setHeader(key,value);`
    • 写响应体
      • 一次性写回响应体:res.end();`
      • 多次写回响应体:res.write();`

    4.2.10 请求与响应

    • 头行体
    • content-type是对请求或者响应体数据,做出的说明

    4.2.11 响应体数据

    • res.write(‘字符串’||读出文件的二进制数据)
    • res.end(‘字符串’||读出文件的二进制数)

    4.2.12 回写页面

    • art-template http
    • 只能是访问 get请求 url: /hero-list 才返回该数据
    • 其他请求返回ok

    4.2.13 jsonp跨域问题

    • 知识点补充

    • url核心对象

    • const url = require('url');
      url.parse('http://xxx.com?id=1',true); // 第二个参数是将id=1转换成对象
      // output:  { protocal:'http',..省略..query:{id:1}   }
      

    4.2.14 CORS跨域问题

    • Access-Control-Allow-Origin: 'http://xxx.com'  //允许哪个域在跨域的时候访问,*代表所有
      // 告诉浏览器,跨域时允许有cookie,同时客户端也要设置withCredentials:true + Origin不能是*
      Access-Control-Allow-Credentials: true  
      Access-Control-Allow-Methods: 'GET,POST,PUT,DELETE';   // 默认允许get/post
      Access-Control-Allow-Headers:'xxx';   // 允许你自己加的头来通信
      
    • 浏览器在非简单请求(get/post)||包含自定义头||content-type非键值对的时候,会先请示服务器,来一个OPTIONS请求,如果不满足,拒绝发送ajax请求

    4.2.15 代理

    • 下载依赖包便于请求操作 npm i request -S

    4.2.16 什么是跨域

    只要协议,域名,端口有任何一个不同,就是跨域

    为什么不能跨域

    浏览器的同源策略,用来保护用户的安全

    4.2.17 跨域的解决方案

    JSONP

    浏览器可以引用不同域下的JS文件,利用这个特性,实现跨域

    get请求

    callback参数

    document.domain

    页面地址是http://a.baidu.com,嵌入的iframe是http://b.baidu.com/

    分别始终hi页面和iframe的document.domain为:baidu.com就可以解决

    CORS方案

    CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问,CORS允许一个域

    向另一个域提交跨域的ajax请求

    header("Access-Control-Allow-Origin","*")
    

    post请求

    反向代理

    正向代理代理的对象是客户端,

    反向代理代理的对象是服务器

    使用HTML5引进的window.postMessage方法来跨域

    个人认为window.name的方法既不复杂也能兼容所有的浏览器

    4.3 express框架

    http://expressjs.com/zh-cn/4x/api.html#app

    4.3.1 请求和响应

    1. request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性。常见属性有

      1. req.app:当callback为外部文件时,用req.app访问express的实例
      2. req.baseUrl:获取路由当前安装的URL路径
      3. req.body / req.cookies:获得「请求主体」/ Cookies
      4. req.fresh / req.stale:判断请求是否还「新鲜」
      5. req.hostname / req.ip:获取主机名和IP地址
      6. req.originalUrl:获取原始请求URL
      7. req.params:获取路由的parameters
      8. req.path:获取请求路径
      9. req.protocol:获取协议类型
      10. req.query:获取URL的查询参数串
      11. req.route:获取当前匹配的路由
      12. req.subdomains:获取子域名
      13. req.accepts():检查可接受的请求的文档类型
      14. req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一个可接受字符编码
      15. req.get():获取指定的HTTP请求头
      16. req.is():判断请求头Content-Type的MIME类型
    2. response 对象表示 HTTP 响应,即在接收到请求时向客户端发送的 HTTP 响应数据。常见属性有:

      1. res.app:同req.app一样
      2. res.append():追加指定HTTP头
      3. res.set()在res.append()后将重置之前设置的头
      4. res.cookie(name,value [,option]):设置Cookie
      5. opition: domain / expires / httpOnly / maxAge / path / secure / signed
      6. res.clearCookie():清除Cookie
      7. res.download(’./xxx.txt’) // 下载文件
      8. res.get():返回指定的HTTP头
      9. res.json({}) // 响应json对象 , 返回ajax数据
      10. res.jsonp(数据) // 配合jsonp 要求客户端请求的时候也是jsonp的方式, 并且callback=xxx
      11. res.location():只设置响应的Location HTTP头,不设置状态码或者close response
      12. res.redirect() // 重定向 301是永久重定向, 302临时重定向
      13. res.render(view,[locals],callback):渲染一个view,同时向callback传递渲染后的字符串,如果在渲染过程中有错误发生next(err)将会被自动调用。callback将会被传入一个可能发生的错误以及渲染后的页面,这样就不会自动输出了。
      14. res.send() // 发送字符串数据自动加content-type
      15. res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
      16. res.sendStatus() // 响应状态码
      17. res.set():设置HTTP头,传入object可以一次设置多个头
      18. res.status():设置HTTP状态码
      19. res.type():设置Content-Type的MIME类型

    4.3.2 路由中间件Router

    • 一个请求进来(总网线),分发到各自不同的处理(分多根网线给其他人)
      • 分流
    • 后端路由
      • (请求方式 + URL = 判断依据)(分流的判断依据) -> 做不同的处理(分流后的行为)
    • 使用步骤
      • 1:获取路由中间件对象 let router = express.Router();
      • 2:配置路由规则 router.请求方式(URL,fn事)
        • fn中参数有req,res,next
      • 3:将router加入到应用app.use(router)

    4.3.4 模板引擎

    使用art-template的模板引擎

    • 下载express-art-template art-template
    • app.js中配置
      • 注册一个模板引擎
        • app.engine('.html',express-art-template);
          • 设置默认渲染引擎app.set('view engine','.html');
      • res.render(文件名,数据对象);
      • express这套使用,默认在当前app.js同级的views目录查找

    4.3.3 静态资源

    Express 提供了内置的中间件 express.static 来设置静态文件如:图片, CSS, JavaScript 等。

    你可以使用 express.static 中间件来设置静态文件路径。例如,如果你将图片, CSS, JavaScript 文件放在 public 目录下,你可以这么写:

    app.use('/public', express.static('public'));//匹配路由public,并将指定的public文件夹映射过去。
    
    • 1: 创建对象 let static = express.static('./public');
    • 2: 配置到中间件中 app.use(static);

    4.3.4 get方法

    var express = require('express');
    var app = express();
     
    app.use('/public', express.static('public'));
     
    app.get('/index.htm', function (req, res) {
       res.sendFile( __dirname + "/" + "index.htm" );
    })
     
    app.get('/process_get', function (req, res) {
       var response = {
           "first_name":req.query.first_name,
           "last_name":req.query.last_name
       };
       console.log(response);
       res.end(JSON.stringify(response));// 输出 JSON 格式
    })
    
    var server = app.listen(8081, function () {
      var host = server.address().address
      var port = server.address().port
      console.log("应用实例,访问地址为 http://%s:%s", host, port)
    })
    

    4.3.5 post方法

    原生的:req.on('data',data=>{ data.toString();})

    var express = require('express');
    var app = express();
    var bodyParser = require('body-parser');
    // 创建 application/x-www-form-urlencoded 编码解析
    // 不用扩展的库来解析键值对,而使用node内置核心对象querystring来解析键值对
    var urlencodedParser = bodyParser.urlencoded({ extended: false })
    
    // 解析application/json
    //app.use(bodyParser.json());
    
    app.use('/public', express.static('public'));
     
    app.get('/index.htm', function (req, res) {
       res.sendFile( __dirname + "/" + "index.htm" );
    })
    app.post('/process_post', urlencodedParser, function (req, res) {
       var response = {
           "first_name":req.body.first_name,
           "last_name":req.body.last_name
       };
       console.log(response);
       res.end(JSON.stringify(response));// 输出 JSON 格式
    })
    app.listen(8081);
    

    4.3.6 文件上传

    var express = require('express');
    var app = express();
    var fs = require("fs");
     
    var bodyParser = require('body-parser');
    var multer  = require('multer');
     
    app.use('/public', express.static('public'));
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(multer({ dest: '/tmp/'}).array('image'));
     
    app.get('/index.htm', function (req, res) {
       res.sendFile( __dirname + "/" + "index.htm" );
    })
    app.post('/file_upload', function (req, res) {
       console.log(req.files[0]);  // 上传的文件信息
       var des_file = __dirname + "/" + req.files[0].originalname;
       fs.readFile( req.files[0].path, function (err, data) {
            fs.writeFile(des_file, data, function (err) {
             if( err ){
                  console.log( err );
             }else{
                   response = {
                       message:'File uploaded successfully', 
                       filename:req.files[0].originalname
                  };
              }
              console.log( response );
              res.end( JSON.stringify( response ) );
           });
       });
    })
    app.listen(8081);
    

    4.3.7 cookie管理

    // express_cookie.js 文件
    var express      = require('express')
    var cookieParser = require('cookie-parser')
    var util = require('util');
    
    var app = express()
    app.use(cookieParser())
     
    app.get('/', function(req, res) {
        console.log("Cookies: " + util.inspect(req.cookies));
    })
    app.listen(8081)
    

    4.3.8 服务端处理错误和404页面找不到

    • 404页面响应router.all('*',()=>{} )
    • 触发错误
      • next(err);
      • 处理错误 app.use( 4参数函数 )

    4.6 koa 框架

    手册地址

    4.6.1 特点

    • 代码编写上避免了多层的嵌套异步函数调用 async await来解决异步(async await 需要依赖于promise)

    • 更轻… 减少了内置的中间件 express.static处理静态资源的内置中间件 express.Router() 路由

    • 启动步骤

      1. 引入Koa构造函数对象 const Koa = require('koa')
      2. 创建服务器示例对象 const app = new Koa();
      3. 配置中间件 app.use(做什么?)
      4. 监听端口启动服务器 app.listen(8888);
    • 做什么? (函数参数说明)

      • context上下文对象: 该对象类似原生http中的 req + res
        • 该对象的req,res属性也存在,就是原生没有包装过的req,res
        • 简单说: context 对象就是从请求到响应 过程中的一个描述对象
      • next函数:调用下一个中间件
    • request(请求对象): 其中包含客户端请求的相关信息

    • response(响应对象): 包含响应数据的具体操作

    aysnc(声明函数中有异步操作)+await(等待) = promise(三合一)

    4.6.2 请求和响应

    request常用属性

    • ctx.request.url(ctx.url)
    • ctx.request.method(ctx.method)
    • ctx.request.headers(ctx.headers)

    response常用属性

    • ctx.response.set(ctx.set) 函数:参数key,val
    • ctx.response.status(ctx.status)
    • ctx.response.body(ctx.body)

    小结

    • 以上所有使用的属性,都可以简写 ctx.xxx
    • 使用async await的应用场景,如果你出现了异步操作,使用其, 后一个中间件使用了async,前后都使用
    • 三主角: 函数前面 async, 内部才能await,要想await能有用,就用promise包裹他

    4.6.3 中间件koa-bodyparser

    支持 json, form and text类型的body体

    • 处理请求体 koa-bodyparser
      • 非GET请求,比如说post请求 ,包括表单提交的form内的数据,都能轻松获取
      • ctx.request.body 获取form中的数据
    • 处理路由 koa-router
    • koa-bodyparser是解析请求体数据的,koa-router中可以通过ctx.query||ctx.params获取url上的参数

    4.3.4 中间件koa-static

    • 处理静态资源 koa-static

    4.3.5 路由

    • 支持app.get,app.put,app.post
    • app.use(router.route())
    • 优化状态码的处理405和501 ,不再是统一的404了

    4.3.5 模板引擎

    • 渲染页面 koa-art-template
      • koa与视图通信的对象 ctx.state

    4.3.6 中间件koa_session

    • session中间件 koa_session
      • sign:true 会生成一个关于cookie数据保障不被修改的签名,如果数据改了,但是签名还是之前的状态,就说明数据不安全
      • app.keys 必须要,内部通过该值进行标识或者说计算
      • 操作session ctx.session.xxx

    4.3.7 koa-socket

    核心思想socket-io

    • 轮询ajax 缺点:不停询问服务器,浪费性能
    • 服务器不关闭连接,一次响应,一直保持连接 缺点:只有服务器向客户端不断输出
    • html5中出来了一个websocket 他是在原来http协议的基础上,去升级当前协议为websocket升级
      • 将原本 先有请求才有响应的机制,更改成了,服务端也可以主动发请求给客户端
      • HTTP 一问一答, TCP协议,客户端与服务器建立连接以后,就可以自由的通信了
      • 缺点:有兼容性问题(IE11)
    • socket.io交互方式可能通过websocket/轮询ajax/服务器响应流(保持连接)
        1. 服务器可主动发数据到客户端
        2. 客户端向客户端发数据通过服务器

    4.8 总结

    • 第三方包的用途 koa-static 处理静态资源
    • koa-router query获取查询字符串 params 获取 /xxx/:id 中的id
    • koa-session app.keys必须要写上作为其内部运算的标识
      • 两次setcookie其中一个是cookie标识
      • 一个是数据签名, 保证数据不被修改
    • koa-art-template 按文档配置引擎
    • koa-bodyparser 解析请求体 ctx.request.body获取数据
    • socket.io
      • 客户端需要引入 socket.io-client
      • 服务器: koa-socket
      • 对象之间的关系和结构,都是写多就熟,也并不用很熟,看着文档,会来就行
      • 客户端端与服务器之间都是 on(‘xxx’) emit(‘xxx’)去对应
        • join加入组
        • to 私聊
        • 事件名,数据 数据可以是对象,如果仅仅是字符串, ctx.data拿就可以了,是对象ctx.data.xxxx

    4.9 events的监听模块emitter

    4.10 nodemon 自动重启组件

    • 修改代码自动重启
    • 安装全局命令行工具 npm i -g nodemon
    • 进入到指定目录命令行 nodemon ./xxx.js
    • 手动触发重启,在命令行输入 rs回车

    配置https

    • 公钥 公开的加密方式
    • 私钥 存在服务器的唯一解公钥加密的方式
    • 签名 确保数据的一致性
    • 证书 确保当前发送数据单位可信
  • 相关阅读:
    我的Android平台“人人相册”客户端
    ADT 17及更高版本的混淆变更
    由glBitmap想到OpenGL编程涉及的坐标系
    版本控制之SVN
    工作了,要努力
    50 Most Frequently Used UNIX / Linux Commands (With Examples)
    linux命令分析SED (二)
    SeekBar也玩分段
    TSQL RAND()
    使用WebClient进行上传文件 [ZT]
  • 原文地址:https://www.cnblogs.com/daozhangblog/p/12446348.html
Copyright © 2020-2023  润新知