• Node.js学习


    Node.js

    新的开始,坚持就是胜利

    基于chrome v8引擎的javascript运行环境
    1、引擎用来解析,执行js代码
    2、提供内置api实现某些功能

    fs文件系统模块

    const fs = require(‘fs’)
    fs.readFile(path[,options],callback) 读取指定文件内容

    • path: 文件路径
    • options: 可选,表示以什么编码格式来读取文件
    • callback: 文件读取完,通过回调函数拿到读取的结果

    fs.writeFile(file,data[,options],callback) 向指定文件写入内容
    -file: 指定一个文件路径的字符串,表示文件存放路径
    -data:写入内容
    -options: 写入文件的内容格式,默认utf-8
    -callback: 文件写入完的回调函数

    	const fs = require('fs')
    	//文件读取
    	fs.readFile('./file.js','utf-8',function(err,data){
    	    console.log(err) //读取失败:err的值为错误对象;读取成功: err = null
    	    console.log('---')
    	    console.log(data);//读取失败,dataStr=undefined
    	})
    	//文件写入
    	fs.writeFile('./files2.txt','hhshshsh',function(err){
    	    console.log(err) //文件写入成功,err = null; 文件写入失败,err = 错误对象
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    处理读取、写入文件时的路径问题

    __dirname: 表示当前文件所处的目录

    • 不会出现路径拼接不好维护,或者相对路径动态拼接的问题
    	const fs = require('fs')
    	let str = ''
    	fs.readFile(__dirname+'/files2.txt','utf8',function(err,data){
    	    if(!err){
    	        str = handleData(data)
    	        fs.writeFile(__dirname+'/files2.txt',str,function(err){
    	            if(err){
    	                console.log('文件写入失败!')
    	            }
    	        })
    	    }else{
    	        console.log('文件读取失败!')
    	    }
    	})
    	const handleData = (str) => {
    	    let newstr = ''
    	    let arr = str.split(' ')
    	    console.log(arr,'arr');
    	    arr.forEach(item => {
    	        let rstr = item.replace('=',':')
    	        newstr += rstr+'\n'
    	    })
    	    console.log(newstr);
    	    return newstr
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    path路径模块

    用来处理路径的模块
    const path = require(‘path’)
    path.join([…paths]),用来将多个路径片段拼接成一个完整的路径字符串

    • …paths路径片段序列
    • 返回值:拼接好的路径的字符串
    • …/有抵消路径的功能

    path.basename(path[,type]), 用来从路径字符串中,将文件名解析出来

    • path: 文件存放路径
    • type: 文件扩展名(.html),使用该参数,该方法会将文件扩展名删除
    • 返回文件名

    path.extname(path), 用来获取路径中的扩展名部分

    • path: 路径
    • 返回 扩展名字符串
    	const path = require('path')
    	const fs = require('fs')
    	
    	fs.readFile(path.join(__dirname,'./file.js'),'utf8',(err,data)=>{
    	    console.log(err,data)
    	    console.log(path.basename(path.join(__dirname,'./file.js'),'.js')) //返回 file
    	    console.log(path.extname(path.join(__dirname,'./file.js')) //返回.js
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    综合案例 - 时钟案例

    实现功能: 将一个包含html、js、css的html文件,分离成html、js、css三个单独的文件,并正常运行功能

    	const fs = require('fs')
    	const path = require('path')
    	
    	const regStyle = /','')
    	    fs.writeFile(path.join(__dirname,'./clock.css'),newCss,(err)=>{
    	        if(err) return console.log('文件写入失败',err.message)
    	        console.log(newCss,'文件写入成功!')
    	    })
    	}
    	
    	const resolveJs = (htmlstr) => {
    	    const r1 = regScript.exec(htmlstr)
    	    const newjs = r1[0].replace('','')
    	    fs.writeFile(path.join(__dirname,'./clock.js'),newjs,(err)=>{
    	        if(err) return console.log('文件写入失败',err.message)
    	        console.log(newjs,'文件写入成功!')
    	    })
    	}
    	
    	const resolveHtml = (htmlstr) => {
    	    let newhtml = htmlstr.replace(regStyle,').replace(regScript,'')
    	    fs.writeFile(path.join(__dirname,'./newclock.html'),newhtml,(err) => {
    	        if(err) return console.log('文件写入失败!',err.message)
    	        console.log(newhtml,'文件写入成功!')
    	    })
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    http模块

    创建web服务器的模块
    const http = require(‘http’)

    创建服务器

    	const http = require('http')
    	const server = http.createServer()
    	
    	server.on('request',(request,response)=>{
    	    console.log(request.url,request.method)
    	    //request: request.url :客户端请求的url地址
    	    //request.method: 客户端请求的method类型
    		response.end(content) , 向客户端响应一些内容
    	})
    	server.listen(8080,()=>{
    	    console.log('server running at http://127.0.0.1:8080')
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    解决中文乱码

    当调用res.end()方法,向客户端发送中文内容的时候,会出现乱码问题,需要手动设置内容的编码格式。

    	server.on('request',(req,res) => {
    		let str = '返回内容'
    		//设置响应头 Content-Type:charset=utf-8
    		res.setHeader('Content-Type','text/html;charset=utf-8')
    		//把包含中文的内容,响应给客户端
    		res.end(str)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    模块化

    把一个大文件拆成独立并互相依赖的多个小模块
    优点:

    • 提高代码复用性
    • 提高代码可维护性
    • 可以实现按需加载

    模块的分类

    内置模块:由node.js官方提供的,如fs、path、http
    自定义模块: 用户创建的js文件
    第三方模块

    加载模块

    require() // 使用该方法加载其他模块时,会执行被加载模块中的代码
    const fs = require(‘fs) //内置
    const custom = require(’./custom.js’)//自定义, 在自定义模块中,默认情况下,module.exports = {}
    const moment = require(‘moment’)//第三方模块

    模块作用域

    类似函数作用域,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问
    优点: 防止全局变量污染

    向外共享模块作用域中的成员

    module对象: 在每个.js自定义模块中,都有一个module对象,它里面存储了和当前模块有关的信息

    • module.exports对象: 将模块内成员共享成员,外界通过require()方法导入自定义模块时,得到的就是module.exports所指向的对象

    exports对象: 简化module.exports,默认情况下,exports和module.exports指向同一个对象,最终共享的结果,以module.export指向的对象为准

    module.exports与exports的使用误区

    在require模块的时候,得到的永远是module.exports指向的对象

    	// test.js
    	exports.username = 'zs'
    	module.exports = {
    		gender:'男',
    		age:20
    	}
    	//require_test.js
    	const test = require('./test')
    	console.log(test) //{gender:'男',age:20}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    上面代码中,改变了module.exports的指向,使module.exports与exports指向不同的对象
    根据规则: 最终共享的结果,以module.export指向的对象为准,不难看出输出结果

    模块化规范

    Common.js模块化规范

    • 每个模块内部,module变量代表当前模块
    • module对象的属性:exports是对外的接口
    • 加载某个模块,其实加载该模块的module.exports属性

    npm&&包

    npm安装指定版本的包:使用@指定版本号

      npm  i  moment@2.22.2
    
    • 1

    模块的加载机制

    模块在第一次加载后会被缓存,这意味着,多次调用require()不会导致模块的代码执行多次(会优先从缓存加载模块)

    • 内置模块加载优先级最高

    express的学习

    express: 专门用来创建web服务器
    基于http内置模块进一步封装出来的

    安装express

    在项目所处目录,运行终端命令,安装express到项目中使用

    	npm i express@4.17.1
    
    • 1

    创建基本的web服务器

    	const express = require('express')
    	//创建web服务器
    	const app = express()
    	//调用app.listen(端口号,启动成功后的回调) ,启动服务器
    	app.listen(80,()=>{
    		console.log('express server running')
    	})
    	//监听get请求
    	app.get('请求url',function(req,res){
    		//处理函数
    		//req.query 默认:空对象
    		//客户端使用?name=zs&age=20 查询字符串形式,发送到服务器的参数,通过req.query.name[age]访问到
    		console.log(req.query) //{name:'zs',age:20}
    		//获取url中的动态参数 req.params
    		// 客户端url: /user/:id (:id 为动态参数)
    		console.log(req.params) // 请求传过来的:{id:value}
    		//向客户端发送json对象
    		res.send({name:'zs',age:20})
    	})
    	//监听post请求
    	app.post('请求url',function(req,res){
    		//处理函数
    		//向客户端发送文本内容
    		res.send('请求成功')
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    托管静态资源

    express.static()
    通过该方法创建一个静态资源服务器

    //假设public目录下包含三个文件:index.html、index.js、index.css
    	app.use(express.static('public')) //指定目录,外界就可以访问指定目录下面的所有文件,但访问路径里不包含public根路径
    	//外界访问路径: localhost:3000/index.html 
    	// ...
    
    • 1
    • 2
    • 3
    • 4

    在托管的静态资源访问路径之前,挂在路径前缀

    	app.use('/front',express.static('public'))
    	//后面访问public目录下的资源时,访问路径需要添加/front
    	//localhost:3000/front/index.html
    
    • 1
    • 2
    • 3

    nodemon 管理项目启动

    使用nodemon工具,可以监听项目文件的变动,当代码修改后,nodemon自动重启项目

    	npm i -g nodemon
    
    • 1

    使用nodemone: 启动node项目的命令由 node app.js 变为 nodemon app.js

    express路由

    在express中,路由指客户端的请求与服务器处理函数之间的映射关系
    分3部分组成:

    • 请求的类型
    • 请求的url地址
    • 处理函数

    路由的匹配过程:按照路由的顺序进行匹配,如果请求类型和请求url同时匹配成功,则express会将这次请求,转交给对应的function函数进行处理

    	app.METHOD(PATH,HANDLER)
    
    • 1

    模块化路由

    创建模块化路由的步骤

    • 创建路由模块对应的js文件
    • 调用express.Router()函数创建路由对象
    • 向路由对象上挂在具体的路由
    • 使用module.exports向外共享路由对象
    • 使用app.use()函数注册路由模块
    	//router.js
    	var express = require('express')
    	var router = express.Router()
    	
    	router.get('/user/list',function(req,res){
    	    res.send('get user list')
    	})
    	router.post('/user/add',function(req,res){
    	    res.send('add new user')
    	})
    	
    	module.exports = router
    
    	//server.js 使用router
    	const express = require('express')
    	const app = express()
    	//引入router对象,挂载到app上
    	const router = require('./router') 
    	app.use(router)
    	
    	app.listen(80,function(){
    	    console.log('启动成功')
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    app.use()的作用,注册全局中间件

    为路由模块添加前缀

    类似静态资源托管时统一挂载访问前缀一样,路由模块添加前缀的方式:

    	app.use('/front',router)
    
    • 1

    express中间件

    作用: 对请求进行预处理
    格式: 本质是一个function处理函数

        //定义一个中间件
    	let express = require('express')
    	let app = express()
    	app.get('/',function(req,res,next){
    		next() //中间件函数的形参列表中,必须包含next参数,路由处理函数只有req,res
    		//next() 作用: 把流转关系,转交给下一个中间件或路由
    	})
    	app.listen(3000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    next函数的作用

    next函数是实现多个中间件连续调用的关键,表示把流转关系转交给下一个中间件或者路由

    全局生效的中间件

    客户端发起的任何请求,到达服务器之后,都会触发的中间件
    定义全局中间件: 通过调用app.use(中间件函数)

    中间件的作用: 多个中间件之间,共享同一份req和res,基于此特性,可以在上游的中间件中,统一为req或res对象添加自定义的属性和方法,供下游的中间件或路由使用
    定义局部生效的中间件: 不使用app.use()定义的中间件

    	const express = require('express')
    	const app = express()
    	//全局中间件
    	app.use((req,res,next)=>{
    	    //由于req\res在多个路由中是共享的
    	    req.startTime = Date.now()
    	    next()
    	})
    	app.get('/user/list',function(req,res){
    	    res.send('get user list'+req.startTime)
    	})
    	
    	app.listen(80,function(){
    	    console.log('启动成功')
    	})
    
    	//局部中间件
    	const midd = function(req,res,next){
    	    console.log('这个是局部中间件')
    	    next()
    	}
    	router.get('/user/list',midd,function(req,res){
    	    res.send('get user list')
    	})
    	//定义多个局部中间件,只在路由内部生效
    	app.get('/',midd1,midd2,midd3...|[midd1,midd2,midd3],(req,res)=>{res.send()})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    使用中间件的注意事项:

    • 一般在路由之前注册中间件,错误级别中间件在所有路由之后,用来捕获错误并返回到也米娜
    • 可以注册多个中间件,在多个中间件之间,共享req,res对象

    中间件分类

    • 应用级别: 绑定到app实例上的中间件(全局/局部)
    • 路由级别: 绑定到router实例上
    • 错误级别: 专门用来捕获整个项目中发生的异常错误,防止项目异常崩溃
    • 内置中间件
    • 第三方中间件
      function(err,req,res,next) 注意是4个参数
    	app.get('/user/list',function(req,res){
    	    throw new Error('服务器内部发生了错误')
    	    res.send('get user list'+req.startTime)
    	})
    	app.use(function(err,req,res,next){
    	    console.log('发生错误;'+err.message);
    	    res.send('error'+ err.message)
    	})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    express内置中间件

    express.static() 托管静态资源的内置中间件
    express.json() 解析json格式的请求体数据
    express.urlencoded() 解析url-encoded格式的请求体数据
    req.body 获取post请求返回来的参数

    	app.use(express.json())
    	app.use(express.urlencoded({extended: false}))
    
    • 1
    • 2

    第三方中间件

    在4.16.0之前版本,经常使用body-parser 第三方中间件,解析请求体数据

    express创建API接口

    express启用cross跨域资源共享

    预检请求

    符合下面任何条件的请求,都需要进行预检请求

    • 请求方式是GET、POST、HEAD之外的method类型
    • 请求头中包含自定义头部字段
    • 向服务器发送了application/json格式的数据

    什么是预检请求:在浏览器与服务器正式通信前,浏览器会发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的OPTION请求称为‘预检请求’。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

  • 相关阅读:
    AB包中的Lua文件应该怎么require
    Boc-QAR-AMC,CAS号:201849-55-0/113866-20-9
    JeeSite快速开发平台 JNPF快速开发平台3.3版本 框架源码部署文档入门说明
    Unity适配微信
    python对RabbitMQ的简单使用
    小白转行做3D游戏建模,有没有前途?
    nodejs+vue教学辅助管理系统
    用Python上傳api資料
    ORACLE APEX-js-获取项的值及json格式化
    Linux网络编程3-select模型
  • 原文地址:https://blog.csdn.net/weixin_37480339/article/details/126123407