node.js

Node.js的学习记录

提示:根据视频学习的一些记录


一、day4的学习内容

1.Express路由

1).初识express中路由

在express中,路由指的是客户端的请求和服务器处理函数之间的映射关系
路由匹配: 按照定义先后顺序进行匹配 ,请求类型和URL同时匹配成功才会调用对应的处理函数。

Express 中的路由分3个部分组成,分别是请求类型、请求的URL地址、处理函数,格式如下:

app.METHOD(PATH,HANDLER)
其中 METHOD :GET、POST   PATH:请求的路径   HANDLER:处理函数
METHOD和PATH是客户端的,HANDLER是服务器端的。

代码示例:

const express = require('express')

const app = express()   //app是服务器实例

//挂载路由
app.get('/',(req,res) => {
    res.end('Hello My girl')
})
app.post('/',(req,res) => {
    res.end('Post requst')
})

app.listen(8080,() => {
    console.log('server running at 127.0.0.1:8080')
})

2).路由模块化

因为app上面代码示例中的app是一个服务器的实例,尽量不要挂载太多的路由,否则文件会很大,所以引出了路由模块化。

第一步:创建路由模块对应的js文件
第二步:调用 experss.Router()函数创建路由对象
第三步:向路由对象挂载具体的路由
第四步:使用 module.exports 向外共享路由对象

代码示例:

//文件名:02.router.js
//这是路由模块
//导入 express
const express = require('express')

//创建路由对象
const router = express.Router()

//挂载具体的路由
router.get('/user/list',(req,res) => {
    res.end('get use list')
})
router.post('/user/add',(req,res) => {
    res.end('Add new user')
})

//向外导出路由对象
module.exports = router

第五步:使用app.use() 函数注册路由模块

代码示例:

const express = require('express')

const app = express()   //app是服务器实例

//1.导入路由模块
const router = require('./02.router')
//2.注册路由模块
app.use(router)
//使用app.use() 挂载统一的前缀  如:app.use('/api',router)
//注意: app.use() 函数的作用,就是用来注册全局中间件(全局中间件,后面讲解)
 
app.listen(8080,() => {
    console.log('server running at 127.0.0.1:8080')
})

2.Express 中间件

中间件:对请求进行预处理,本质上是一个function()函数,但是形参由req,res,next三部分组成。

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

中间件的作用多个中间件之间,共享一份 req 和 res。基于这样的特性,就可以在上游的中间件中,统一为 req 或 res 对象添加属性和方法,供下游的的中间件或路由使用。

注意:中间件一定要在路由之前定义,中间件一定要调用next()函数

1).最简单的中间件函数

代码示例如下:

const express = require('express')
const app = express()  //app是服务器实例

//定义一个最简单的中间件函数
const mv = function (req,res,next){
    console.log('这是最简单的中间件函数')
    //把流转关系,转交给下一个中间件或路由
    next()
}

app.listen(8080,() => {
    console.log('server running at http://127.0.0.1:8080')
})

2).全局中间件的使用

通过定义app.use() 来定义一个全局中间件,形参是一个中间件函数。

示例代码如下:

const express = require('express')
const app = express()  //app是服务器实例

//定义一个最简单的中间件函数
const mv = function (req,res,next){
    console.log('这是最简单的中间件函数')
    //把流转关系,转交给下一个中间件或路由
    next()
}

//将 mv 注册为全局中间件
app.use(mv)

app.get('/',(req,res) => {
    console.log('调用了 / 这个路由')
    res.end('Home page')
})
app.get('/user',(req,res) => {
    console.log('调用了 /user 这个路由')
    res.end('User page')
})

app.listen(8080,() => {
    console.log('server running at http://127.0.0.1:8080')
})

其中定义中间件函数和注册全局中间件可以和并在一起

app.use((req,res,next) => {
    console.log('这是最简单的中间件函数')
    next()
})
3).中间件的作用

代码示例如下:

const express = require('express')
const app = express()  //app是服务器实例

//这是中间件的简化形式
app.use((req,res,next) => {
    //获取到达服务器的时间
    const time = Date.now()
    //为 req 对象挂载自定义属性,从而把时间共享给后面的所有路由
    req.startTime = time
    next()
})

app.get('/',(req,res) => {
    console.log('调用了 / 这个路由')
    res.end('Home page' + req.startTime)
})
app.get('/user',(req,res) => {
    console.log('调用了 /user 这个路由')
    res.end('User page' + req.startTime)
})

app.listen(8080,() => {
    console.log('server running at http://127.0.0.1:8080')
})
4).多个中间件

可以使用多个app.use() 连续定义多个全局中间件。客户端请求到达服务器之后,会按照中间件定义的先后顺序,依次进行调用。

代码示例如下:

const express = require('express')
const app = express()
//定义第一个中间件
app.use(function(req,res,next){
    console.log('这是第一个中间件')
    next()
})
//定义第二个中间件
app.use(function(req,res,next){
    console.log('这是第二个中间件')
    next()
})
app.get('/user',(req,res) => {
    res.end('Home age.HAHAHAHA')
})
app.listen(8080,() =>{
    console.log('sever running at http://127.0.0.1:8080')
})

运行结果如下:

sever running at http://127.0.0.1:8080
这是第一个中间件
这是第二个中间件
5).局部生效中间件

代码示例如下:

const express = require('express')
const app = express()
//1.定义一个中间件函数
const mw1 = function (req,res,next){
    console.log('调用了局部生效的中间件函数')
    next()
}
//2.创建路由
app.get('/',mw1,(req,res) =>{   //调用局部生效中间件mw1
    res.send('Home page XIXIXIXI')
})
app.get('/user',(req,res) =>{
    res.send('User page HAHAHAHA')
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

代码运行结果:

//在 Airpost 中测试 http://127.0.0.1:8080/ 的终端结果
server running at http://127.0.0.1:8080
调用了局部生效的中间件函数

//在 Airpost 中测试 http://127.0.0.1:8080/user 的终端结果
server running at http://127.0.0.1:8080
6).多个局部中间件

代码示例如下:

const express = require('express')
const app = express()
//1.定义中间件函数
const mw1 = function (req,res,next){
    console.log('调用了第一个局部生效的中间件函数')
    next()
}
const mw2 = function (req,res,next){
    console.log('调用了第二个局部生效的中间件函数')
    next()
}
//2.创建路由
app.get('/',mw1,mw2,(req,res) =>{   //调用局部生效中间件mw1和mw2
    res.send('Home page XIXIXIXI')
})
app.get('/user',(req,res) =>{
    res.send('User page HAHAHAHA')
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

其中 mw1,mw2 可以完全等价于 [mw1,mw2] 这样的效果是一样的

运行的终端结果

//在 Airpost 中测试 http://127.0.0.1:8080/ 的终端结果
server running at http://127.0.0.1:8080
调用了第一个局部生效的中间件函数
调用了第二个局部生效的中间件函数

//在 Airpost 中测试 http://127.0.0.1:8080/user 的终端结果
server running at http://127.0.0.1:8080
7).错误级别中间件

作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃问题。
错误级别的中间件,一个错误级别的中间件是不需要使用 next() 函数,而且必须注册在所有路由之后

代码示例如下:

const express = require('express')
const app = express()
//1.定义路由
app.get('/',(req,res) =>{
    //1.1认为制造错误
    throw new Error('服务器发生了内部错误!')
    res.send('Home page')
})
//2.定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃
app.use(function(err,req,res,next){
    console.log('发生了错误!'+ err.message)
    //向服务器相应错误内容
    res.end('Error!'+err.message)
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

代码运行结果如下:

//终端结果:
server running at http://127.0.0.1:8080
发生了错误!服务器发生了内部错误!

//Airpost接口测试返回结果:
Error!服务器发生了内部错误!
8).express内置中间件

express.static —前面已经使用过了;
express.json 解析JSON格式的请求体数据(有兼容性,只能在4.16.0之后的版本使用);
express.urlencoded 解析URL-encoded格式的请求体数据(有兼容性,只能在4.16.0之后的版本使用)。
express.json 在使用Airpost时,应换到application/josn;
express.urlencoded 在使用Airpost时,应该换到application/x-www-from-urlencoded

express.json 代码示例如下:

const express = require('express')
const app = express()
//注意:除了错误级别的中间件,其他中间件,必须在路由之前配置
//通过 express.josn() 这个中间件,解析表单中的JSON格式的数据
app.use(express.json())
app.post('/',(req,res) =>{
    //在服务器可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
    //默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined
    console.log(req.body)
    res.end('ok')
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

运行终端结果如下:

server running at http://127.0.0.1:8080
{ name: 'zs', age: 20 }

express.urlencode 代码示例如下:

const express = require('express')
const app = express()
//注意:除了错误级别的中间件,其他中间件,必须在路由之前配置
//通过 express.urlencoded() 这个中间件,解析表单中的url-encoded 格式的数据
app.use(express.urlencoded({extended:false}))
app.post('/book',(req,res)=>{
    console.log(req.body)
    res.end('ok')
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

运行终端结果如下:

server running at http://127.0.0.1:8080
[Object: null prototype] { bookname: '水浒传', author: '施耐庵' }
9).第三方中间件

body-parse 第三方中间件,这个跟内置的 express.urlencode 十分相似。
先在终端输入 npm i body-parser 安装好 body-parser
body-parser 在使用Airpost时,应该换到application/x-www-from-urlencoded

代码示例:

const express = require('express')
const app = express()
// 1.导入解析表单数据的中间件 body-parse
const parser = require('body-parser')
//2,使用 app.use() 注册中间件
app.use(parser.urlencoded({extended:false}))
app.post('/user',(req,res) =>{
    //如果没有配置任何解析表单数据的中间件, 则req.body 默认等于 undefined
    console.log(req.body)
    res.end('ok')
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

运行在终端结果:

server running at http://127.0.0.1:8080
[Object: null prototype] { name: '张三', age: '19' }
10).封装自定义的中间件

自定义的中间件实现步骤:
a.定义中间件
b.监听 req 的 data 事件
c.监听 req 的 end 事件(next () 一定放在此部分结尾处)
d.使用 querystring 模块解析请求体数据
e.将解析出来的数据对象挂载为 req.body
f.将自定义中间件封装为模块

模块文件代码示例:

//4.1 导入 Node.js 中内置的 querystring 模块
const qs = require('querystring')

//这是解析表单数据的中间件
const bodyParser = (req,res,next) => {
    //定义中间体的具体业务逻辑
    //1.定义一个 str 字符串,专门用来存储客户端发送过来的请求体数据
    let str = ''
    //2.监听 req 的 data 事件
    req.on('data',(chunk) =>{
        str += chunk
    })
    //3.监听 req 的 end 事件
    req.on('end',() =>{
        //在 str 中存放的是完整的请求数据
        // console.log(str)  结果:name=%E5%BC%A0%E4%B8%89&age=19&gender=%E7%94%B7&
        //TODO:把字符串格式的请求体数据,解析成对象格式,使用 qs.parse() 方法,将查询字符串解析为对象
        const body = qs.parse(str)
        // console.log(body)   //结果:[Object: null prototype] { name: '张三', age: '19', gender: '男' }
        // 挂载
        req.body = body
        next()
    })
}
module.exports = bodyParser

调用自定义中间件代码示例:

const express = require('express')
const app = express()

//1.导入自己封装的中间件模块
const customBodyParser = require('./11.custom-body-parser')
//2. 将自定义的额中间件函数,注册为全局可用的中间件
app.use(customBodyParser)
app.post('/user',(req,res)=>{
    res.send(req.body) 
})
app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

运行结果:
在这里插入图片描述

3.使用Express写接口

第一,创建express服务器
第二,创建API路由模块
第三,编写GET接口或POST接口

1).GET接口

Airpost在Query里面填写传输的参数,测试接口的路径是http://127.0.0.1:8080/api/get

代码实现示例:

//文件名:13.apiRouter.js
const express = require('express')
const router = express.Router()

//在这里挂载对应的路由
router.get('/get',(req,res) => {
    //通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
    const query = req.query
    //
    console.log(query)
    res.send({
        status:0,  //0 表示处理成功,1 表示处理失败
        msg :'GET请求成功!', //状态的描述
        data: query //需要响应给客户端的数据
    })
})

module.exports = router
//文件名:12.UseExpressjeikou.js
const express = require('express')
const app = express()  //服务器实例对象

//1.导入路由模块,也算中间件
const router = require('./13.apiRouter')

//把路由模块注册到app上
app.use('/api',router)

app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

2).POST接口

注意此处:要先挂在解析urlencoded的工具(配在我们需要请求的那个文件),再挂载router
在使用Airpost时,传递的参数应该换到application/x-www-from-urlencoded,然后再输入

代码实现示例:

//文件名:13.apiRouter.js
const express = require('express')
const router = express.Router()

//在这里挂载对应的路由
router.post('/post',(req,res) => {
    //通过 req.body 获取请求体中办函的 url-encoded 格式的数据
    const body = req.body
    console.log(body)
    res.send({
        status:0,  //0 表示处理成功,1 表示处理失败
        msg :'POST请求成功!', //状态的描述
        data: body //需要响应给客户端的数据
    })
})

module.exports = router
3).CORS跨域资源共享

新增部分代码:

//一定要在路由之前,配置 cors 这个文件,从而解决接口跨域问题
const cors = require('cors')
app.use(cors())
//网页代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <title>test</title>
</head>
<body>
    <button id="button1">GET</button>
    <button id="button2">POST</button>
</body>
<script>
    $(function(){
        //1.测试GET接口
        $("#button1").on('click',function(){
            $.ajax({
                type:'GET',
                url:'http://127.0.0.1:8080/api/get',
                data :{
                    name: 'zs',
                    age: 20
                },
                success: function(res){
                    console.log(res)
                }
            })
        })
        //2.测试POST接口
        $("#button2").on('click',function(){
            $.ajax({
                type:'POST',
                url:'http://127.0.0.1:8080/api/post',
                data :{
                    bookname:'水浒传',
                    author : '施耐庵'
                },
                success: function(res){
                    console.log(res)
                }
            })
        })
    })
</script>
</html>
//接口文件代码:
const express = require('express')
const app = express()

//一定要在路由之前,配置 cors 这个文件,从而解决接口跨域问题
const cors = require('cors')
app.use(cors())

//1.导入路由模块,也算中间件
const router = require('./13.apiRouter')
//配置解析表单数据的中间件
app.use(express.urlencoded({extended:false}))

//把路由模块注册到app上
app.use('/api',router)

app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})
4).CORS响应头

Access-Control-Allow-Origin

指定允许访问该资源的外域URL,例如:

res.setHeader('Access-Control-Allow-Origin','http://itcast.cn')

表示允许来自任何域的请求,例如:

res.setHeader('Access-Control-Allow-Origin','*')

Access-Control-Allow-Headers

默认情况下,CORS仅支持客户端向服务器发送如下的9个请求头:
Accept、Accept-Language、 Content-Language、 DPR、 Downlink、 Save- Data、Viewport-Width、 Width 、
Content-Type (值仅限于 text/plain. multipart/form data、application/x-www form-urlencoded三者之一)
如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!

1 //允许客户端额外向服务器发送Content-Type 请求头和X-Custom-Header 请求头
2 //注意:多个请求头之间使用英文的逗号进行分割
3 res . setHeader( ' Access-Control -Allow-Headers', ' Content-Type, X- Custom-Header ')

Access-Control-Allow-Methods

默认情况下,CORS仅支持客户端发起GET、POST、 HEAD请求(即简单请求)。
如果客户端希望通过PUT、DELETE 等方式请求服务器的资源,则需要在服务器端,通过Access-Control-Alow-Methods来指明实际请求所允许使用的HTTP方法。

示例代码:

//只允许POST. GET、 DELETE HEAD 请求方法
res.setHeader( 'Access- Control -Allow-Methods', 'POST, GET, DELETE, HEAD')
//允许所有的HTTP 请求方法
res.setHeader( ' Access-Control -Allow-Methods', '* )
5).简单请求和预检请求

简单请求:客户端和服务器之间只会发生一次请求。
预检请求:客户端和服务器之间会发生两次请求,OPTION预检请求成功之后,才会发起真正的请求。

6).JSONP接口

定义:浏览器通过 <script> 标签的src属性,请求服务器上的数据,同时,服务器返回一个函数的调用。
特点:JSONP不属于Ajax请求,因为它没有使用XMLHttpRequest这个对象。
           JSONP仅支持GET请求,不支持POST、PUT、DELETE等请求。

注意:如果项目中已经配置了CORS跨域资源共享,为了防止冲突,一定要在配置CORS中间件之前声明JSONP的接口,否则,JSONP接口会被处理成开启了CORS的接口。

新增部分代码:

//必须在配置 CORS中间件之前,配置 JSONP 接口
app.get('/api/jsonp',(req,res) => {
    //TODO:定义 JSONP 接口具体的实现过程
    //1.得到函数的名称
    const funcName = req.query.callback;
    //2.定义要发送到客户端的数据对象
    const data = {name: 'zs',age: 20}
    //3.拼接出一个函数的调用
    const scriptStr = `${funcName}(${JSON.stringify(data)})`
    //4.把拼接的字符串响应给客户端
    res.send(scriptStr)
})
//网页代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./jquery/jquery-3.1.1.min.js"></script>
    <title>test</title>
</head>
<body>
    <button id="button1">GET</button>
    <button id="button2">POST</button>
    <button id="button3">DELETE</button>
    <button id="button4">JSONP</button>
</body>
<script>
    $(function(){
        //1.测试GET接口
        $("#button1").on('click',function(){
            $.ajax({
                type:'GET',
                url:'http://127.0.0.1:8080/api/get',
                data :{
                    name: 'zs',
                    age: 20
                },
                success: function(res){
                    console.log(res)
                }
            })
        })
        //2.测试POST接口
        $("#button2").on('click',function(){
            $.ajax({
                type:'POST',
                url:'http://127.0.0.1:8080/api/post',
                data :{
                    bookname:'水浒传',
                    author : '施耐庵'
                },
                success: function(res){
                    console.log(res)
                }
            })
        })
        //3.为删除按钮绑定点击事件处理函数
        $('#button3').on('click',function(){
            $.ajax({
                type:'DELETE',
                url:'http://127.0.0.1:8080/api/delete',
                success:function(res){
                    console.log(res)
                }
            })
        })
        //4.为JSONP按钮绑定点击事件处理函数
        $('#button4').on('click',function(){
            $.ajax({
                type:'GET',
                url:'http://127.0.0.1:8080/api/jsonp',
                dataType:'jsonp',
                success:function(res){
                    console.log(res)
                }
            })
        })
    })
</script>
</html>
//接口文件代码:
const express = require('express')
const app = express()

//配置解析表单数据的中间件
app.use(express.urlencoded({extended:false}))

//必须在配置 CORS中间件之前,配置 JSONP 接口
app.get('/api/jsonp',(req,res) => {
    //TODO:定义 JSONP 接口具体的实现过程
    //1.得到函数的名称
    const funcName = req.query.callback;
    //2.定义要发送到客户端的数据对象
    const data = {name: 'zs',age: 20}
    //3.拼接出一个函数的调用
    const scriptStr = `${funcName}(${JSON.stringify(data)})`
    //4.把拼接的字符串响应给客户端
    res.send(scriptStr)
})

//一定要在路由之前,配置 cors 这个文件,从而解决接口跨域问题
const cors = require('cors')
app.use(cors())

//1.导入路由模块,也算中间件
const router = require('./13.apiRouter')

//把路由模块注册到app上
app.use('/api',router)

app.listen(8080,() =>{
    console.log('server running at http://127.0.0.1:8080')
})

版权声明:本文为qq_51371436原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。