Node.js笔记

Node.js笔记

在@ Sherry 沈文章的基础上加了一点自己的思考。原文链接:Node.js最新版黑马配套笔记

初始 nodejs与内置模块

回顾与思考

  1. 浏览器中的js组成部分

    • JS核心语法
    • webAPI
  2. 为什么js可以操作DOM和BOM

    #TODO:

    • 知道什么是DOM和BOM
NODEJS简介
  1. 什么是Node.js?
    Node.js是一个基于Chrome V8引擎的JS运行环境
  2. Node.js中的JS运行环境
    V8引擎和内置API函数
  • 浏览器是JS的前端运行环境
  • Node.js是Js的后端运行环境
  • Node.js中无法调用DOM和BOM等浏览器内置API
  1. NODEJS可以做什么

image.png

  1. NODEJS学习路径

JS基础语法- Node.js内置API模块(fs,path,http)-第三方API模块(express,mysql)

fs文件系统模块

读取指定文件中的内容

fs.readFile(path[,options],callback)
  • 参数1:必选参数,字符串,表示文件的路径
  • 参数2:可选参数,表示以什么编码格式来读取文件
  • 参数3:必选参数,文件读取完成后,通过回调函数拿到读取的结果。

使用方法:

// 1.导入fs模块,来操作文件
const fs = require('fs')
// 2.调用fs.readFile()方法读取文件
fs.readFile('./file/1.txt', 'utf8', function (err, dataStr) {
    // 打印失败的结果,如果读取成功,则err的值为null
    // 如果读取失败,则err的值为错误对象,dataStr的值为undefined
    if (err) {
        return console.log('读取文件失败' + err.message)
    }
    console.log('读取文件成功' + dataStr)

})
向指定文件中写入内容
fs.writeFile(file, data[, options], callback)
  • 参数1:必选参数,字符串,表示文件的存放路径
  • 参数2:必选参数,表示要写入的内容
  • 参数3:可选参数,表示以什么编码格式来读取文件,默认值是utf8
  • 参数4:必选参数,文件写入完成后的回调函数。

使用方法:

// 1.导入fs模块,来操作文件
const fs = require('fs')
// 2.调用fs.writeFile()方法读取文件
fs.writeFile('./file/1.txt', 'abcd', function (err) {
    // 打印失败的结果,如果读取成功,则err的值为null
    // 如果读取失败,则err的值为错误对象,dataStr的值为undefined
    if (err) {
        return console.log('读取文件失败' + err.message)
    }
    console.log('写入文件成功' )

})
案例:考试成绩整理

核心实现步骤

  • 导入需要的fs文件系统模块
  • 使用fs.readFile()方法,读取素材目录下的成绩.txt文件
  • 判断文件是否读取失败
  • 文件读取成功后,处理成绩数据
  • 将处理完成的成绩数据,调用fs.writeFile()方法,写入到新文件中
// 导入fs模块
const fs = require('fs')
// 2.调用fs.readFile()方法读取文件
fs.readFile('./file/2.txt', 'utf8', function (err, dataStr) {
    // 打印失败的结果,如果读取成功,则err的值为null
    // 如果读取失败,则err的值为错误对象,dataStr的值为undefined
    // 3.判断文件是否读取成功
    if (err) {
        return console.log('读取文件失败' + err.message)
    }
    console.log('读取文件成功' + dataStr)


    // 4.1先把成绩的数据,按照空格进行分割
    const arrOld = dataStr.split(' ')
    // 4.2循环分割后的数组,对每一项的数据,进行字符串的替换操作
    const arrNew = []
    arrOld.forEach(item => {
        arrNew.push(item.replace('=', ':'))
    })
    console.log(arrNew)
    // 4.3把新数组中的每一项,进行合并,得到新的字符串
    const newStr = arrNew.join('\n\r')
    console.log(newStr)
    // 5.调用fs.writeFile()方法,把处理完毕的成绩,写入到新文件中
    fs.writeFile('./file/成绩ok.txt', newStr, function (err) {
        if (err) {
            return console.log('写入文件失败!' + err.message)
        }
        console.log('写入文件成功!')
    })
})
  • 理解这里的源码

如果使用相对路径很容易出问题:./ …/,所以建议直接使用绝对路径

path路径模块

path路径模块是什么

path模块是Node.js官方提供的,用来处理路径的模块,它提供一系列的方法和属性,用来满足用户对于路径的处理需求

image.png
如果要在JS代码中,使用path模块来处理路径,则需要使用以下的方式先导入它

const path=require('path')
path.join()语法格式
path.join([...paths])

image.png

path.basename()

使用改方法可以获取路径的最后一部分

path.basename(path[,ext])

参数:path:必选参数,表示一个路径的字符串
ext可选参数,表示文件拓展名
返回:表示路径中的最后一部分

image.png

path.extname()

获取路径中的拓展名部分

path.extname()

image.png

案例:时钟
// 1.1 导入需要的模块并创建正则表达式
const fs=require('fs')
// 1.2导入path路径处理模块
const path=require('path')
// 1.3匹配标签
// 其中\s表示空白字符,\S表示非空白字符,*表示匹配任意次
const regStyle=/<style>[\s\S]*<\style>/
// 1.4匹配<stript></stript>标签的正则
const regScript=/<script>[\s\S]*<script>/

http模块

什么是客户端?什么是服务器

在网络资源中负责消费网络资源的电脑叫做客户端

负责对外提供网络资源的电脑叫做服务器

Http模块是Node.js官方提供的,用来创建web服务器的模块。通过http模块提供的Http.createServer()方法,就能方便的把一台普通电脑,变成一台web服务器,从而对外提供Web资源服务。

服务器相关概念

image.png

image.png

image.png

创建最基本的web服务器

创建web服务器实例
const server=http.createServer()
为服务器实例绑定request事件,监听客户端的请求
//使用服务器实例的.on()方法,为服务器绑定一个request事件
server.on('request',(req,res)=>{
//只要有客户端来请求我们自己的服务器,就会触发request事件,从而调用这个事件处理函数
console.log('someone visit our web server.')
})
启动服务器
//调用server.listen(端口号,cb回调)方法,即可启动web服务器
server.listen(80,()=>{
console.log('http server running at http://127.0.0.1')
})
req请求对象

只要服务器接收到了客户端的请求,就会调用server.on()为服务器绑定的request事件处理函数
如果想在事件处理函数中,访问与客户端相关的数据或属性,可以使用如下的方式:

server.on('request',(req,res)=>{
//req是请求对象,它包含了与客户端相关的数据和属性,例如:
//req.url是客户端相关的数据和属性,例如:
//req.url是客户端请求的url地址
//req.method 是客户端的method请求类型
const str='Your request url is ${req.url},and request method is ${req.method}'
console.log(str)
}
res响应对象
server.on('request',(req,res)=>{
//res是响应对象,它包含了与服务器相关的数据和属性,例如:
//要发送到客户端的字符串
const str='Your request url is ${req.url},and request method is ${req.method}'
//res.end()方法的调用:
//向客户端发送指定内容,并结束这次请求的处理过程
res.end(str)
}

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

server.on('request',(req,res)=>{
//发送的内容包含中文
const str='您请求的url地址是${req.url},请求的method类型是${req.method}'
//为了防止中文显示乱码的问题,需要设置响应头
res.setHeader('Content-Type','text/html;charset=utf-8')
//把包含中文的内容,响应给客户端
res.end(str)
})

4.6根据不同的url响应不同的html内容

server.on('request',function(req,res){
const url =req.url
//1.获取请求的Url地址
let str ='<h1>404 Not found!</h1>'
//2.设置默认的内容
if(url=='/'||url ==='/index.html'){
str='<h1>首页</h1>'
//3.用户请求的是首页
}else if(url==='/about.html'){
str='<h1>关于页面</h1>'
}
//为了防止中文显示乱码的问题,需要设置响应头
res.setHeader('Content-Type','text/html;charset=utf-8')
//把包含中文的内容,响应给客户端
res.end(str)
})

这里我的理解是:res.end是返回res,res中本来就是包含content的,所以server.on会根据不同的req修改content然后返回

模块化

模块化的基本概念

什么是模块化?

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程。对于整个系统来说,模块是可组合、分解和变换的单元
编程领域中的模块化:就是遵守固定的规则,把一个大文件拆成独立并且互相依赖的多个小模块。

Node.js中的模块化

根据模块来源的不同,将模块分为了三大类,分别是:
内置模块(fs,path,http)
自定义模块(用户创建的每个Js文件)
第三方模块(由第三方开发出来的模块)

什么是模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域
防止了全局变量污染的问题
向外共享模块作用域中的成员

module对象和exports对象

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

可以使用该对象将模块内的成员共享出去,供外界使用。外界用require方法导入自定义模块时,得到的就是Module.exports所指的对象

exports对象
由于module.exports单词写起来比较复杂,为了简化向外共享成员的代码,Node提供了exports对象。默认情况下,exports和module.exports指向同一个对象,最终共享的结果,还是以module.exports指向的结果为准

exports和module.exports的使用误区

image.png

npm与包

格式化时间的高级做法
  1. 使用npm包管理工具,在项目中安装格式化时间的包moment

  2. 使用require()导入格式化时间的包

  3. 参考Moment的官方API文档对时间进行格式化

//1.导入Moment包,注意导入的名称,就是装包时候的名称
const moment = require('moment')//注意是字符串node 6    

const dt = moment().format('YYYY-MM-DD HH:mm:ss')
console.log(dt)

包管理配置文件
  1. 多人协作的问题:第三方的包的体积过大,不方便成员之间共享项目源代码
    解决方案:共享时剔除node_modules

  2. 在项目根目录中,创建一个叫做package.json的配置文件,即可用来记录在项目中安装了哪些包,从而方便剔除node_modules目录之后,在团队成员之间共享项目的源代码
    今后在项目开发中,一定要把Node_modules文件夹,添加到.gitignore忽略文件夹中

  3. npm包管理工具提供了一个快捷命令,可以在执行命令时所处的目录中,快速创建package.json这个包管理配置文件:

npm init -y

上述命令只能在英文的目录下运行成功!所以项目文件夹的名称一定要使用英文命名,不能出现空格。运行npm install命令安装包的时候,npm包管理工具,会自动把包的名称和版本号,记录到package.json中

  1. 一次性安装所有包
    可以运行npm install命令,一次性安装所有安装所有的依赖包
//执行npm install 命令时,npm 包管理工具会先读取package.json中的dependencies节点
//读取到记录的所有依赖包名称和版本号之后,包管理工具会把这些包一次性的下载到项目中去
npm install 
  1. 卸载包
    可以npm uninstall
//使用npm uninstall 具体的包名 来卸载包
npm uninstall moment
nrm

为了更方便的切换下包镜像源,我们可以安装nrm这个小工具,利用nrm提供的终端命令,可以快速查看和切换下包的镜像源

//通过npm包管理工具,将nrm安装为全局可用的工具
npm i nrm -g
//查看所有能用的镜像原
nrm ls
//将下包的镜像原切换为taobao镜像
nrm use taobao
规范包的结构

image.png

模块的加载机制

优先从缓存中加载
模块在第一次被加载后会被缓存。这也意味着多次调用require()不会导致模块的代码被多次执行。注意:不论是内置模块,自定义模块,还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。
内置模块的加载机制
内置模块加载优先级最高。
自定义模块的加载机制
使用require()加载自定义模块时,必须指定以./或…/开头的路径标识符。在加载自定义模块时,如果没有指定的话,则node模块就会把他当成内置模块或者第三方模块进行加载
同时,在使用require()导入自定义模块时,如果省略了文件的拓展名,则node.js就会按顺序分别尝试加载以下的文件
1.按照确切的文件名进行加载
2.补全.js拓展名进行加载
3.补全.json拓展名进行加载
4.补全.node拓展名进行加载
5.加载失败,终端报错
第三方模块的加载机制
如果传递给require()的模块标识符不是一个内置模块,也没有./等等开题,则Node.js会从当前模块的父目录开始,尝试从.node_modules文件夹中加载第三方模块。如果没有找到第三方模块,则移动到再上一层父目录中,进行加载,直到文件系统的根目录
目录作为模块

  • 如何开发属于自己的包
  • 12

express

express 简介

Express是基于Node.js平台,快速,开放,极简的Web开发框架

express的安装
在项目所处的目录中,运行如下的终端命令,即可将express安装到项目中使用:

npm i express@4.17.1

使用express创建最基本的服务器

//1.导入express
const express = require('express')
//2.创建web服务器
const app = express()
//3.启动web服务器
app.listen(80, () => {
    console.log('express server running at http://127.0.0.1')
})

Express 的基本使用

监听GET请求和POST请求

//参数1:客户端请求的url地址
//参数2:请求对应的处理函数
//req:请求对象(包含了与请求属性相关的属性与方法)
//res:响应对象(包含了与响应对象相关的属性与方法)
app.get('请求url',function(req,res){/*处理函数*/})

把get改为post就是post请求

把内容响应给客户端
通过res.send()方法,可以把处理好的内容,发送给客户端

app.get('/user',(req,res)=>{
//向客户发送json请求
res.send({name:'zs',age:20,gender:'男'})
})
app.post('/user',(req,res)=>{
//向客户端发送文本内容
res.send('请求帮助')
})

send可以发送文本内容,也可以发送json数据

获取URL中携带的查询参数

通过req.query对象,可以访问到客户端通过查询字符串的形式,发送到服务器的参数:

app.get('/', (req, res) => {
    //通过req.query可以获取到客户端发送过来的查询参数
    //注意:在默认情况下,req.query是一个空对象
    //客户端使用?name=zs&age=20这种查询字符串形式,发送到服务器参数
    //可以通过req.query对象访问到,例如:
    //req.query.name req.query.age
    console.log(req.query)
    res.send(req.query)

})

获取URL中的动态参数

通过req.params对象,可以访问到Url中,通过:匹配到的动态参数

//url地址中,我们开业通过:参数名的形式,匹配动态参数值
app.get('user/:id',(req,res)=>{
//req.params默认是一个空对象
//里面存放这通过:动态匹配到的参数值
console.log(req.params)
})

汇总

//1.导入express
const express = require('express')
//一般情况下不需要手动导入response模块,因为在路由处理函数中 `response`对象已经默认可用。
const res = require('express/lib/response')
//2.创建web服务器
const app = express()
//4.监听客户端的GET和POST请求,并向客户端响应具体的内容
app.get('/user', () => {
    //调用express提高的res.send()方法,向客户端响应一个json对象
    res.send({ name: 'zs', age: 20, gender: '男' })
})
app.post('/user', (req, res) => {
    //调用express提供的res.send()方法,向客户端响应一个文本字符串
    res.send('请求成功')
})
app.get('/', (req, res) => {
    //通过req.query可以获取到客户端发送过来的查询参数
    //注意:在默认情况下,req.query是一个空对象
    console.log(req.query)
    res.send(req.query)

})
//url地址中,我们开业通过:参数名的形式,匹配动态参数值
app.get('/user/:id', (req, res) => {
    //req.params默认是一个空对象
    //里面存放这通过:动态匹配到的参数值
    console.log(req.params)
    res.send(req.params)
})
//3.启动web服务器
app.listen(80, () => {
    console.log('express server running at http://127.0.0.1')
})

托管静态资源

  1. express.static()

image.png
默认情况下:目录名不会出现在URL中

  1. 托管多个静态目录

访问静态资源文件时,express.static()会根据目录的添加顺序查找所需的文件

image.png

  1. 挂载路径前缀

image.png

nodemon

普通的node命令修改项目之后需要手动修改项目,但是nodemon会自动监听修改,然后自动重启项目

node app.js
//将上面的终端命令,替换为下面的终端命令,即可实现自动重启项目的效果
nodemon app.js

express路由

路由的概念

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

app.METHOD(PATH,HANDLER)

也就是说method和path是用来识别一个路径的,handler只是识别出来之后的处理程序而已

路由的使用

模块化路由:为了方便对路由进行模块化的管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。将路由抽离为单独模块的步骤如下:

  1. 创建路由模块对应的.js文件
  2. 调用express.Router()函数创建路由对象
  3. 向路由对象挂载具体的路由
  4. 使用module.exports向外共享路由对象
  5. 使用app.use()函数注册路由模块

创建路由模块

// 这是路由模块
// 1. 导入 express
const express = require('express')
// 2. 创建路由对象
const router = express.Router()

// 3. 挂载具体的路由
router.get('/user/list', (req, res) => {
  res.send('Get user list.')
})//获取挂载用户列表的路由
router.post('/user/add', (req, res) => {
  res.send('Add new user.')
})//获取添加用户的路由
// 4. 向外导出路由对象
module.exports = router

注册路由模块

// 1. 导入路由模块
const router = require('./03.router')
// 2. 注册路由模块
app.use(router)

为路由模块添加前缀

// 1. 导入路由模块
const router = require('./03.router')
// 2. 注册路由模块,使用app.use()注册路由模块,并添加统一的访问前缀/api
app.use('/api', router)

全部代码

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

// app.use('/files', express.static('./files'))

// 1. 导入路由模块
const router = require('./03.router')
// 2. 注册路由模块
app.use('/api', router)

// 注意: app.use() 函数的作用,就是来注册全局中间件

app.listen(80, () => {
  console.log('http://127.0.0.1')
})

express中间件

Express中间件的概念

当请求到express服务器之后由中间件进行处理,我认为所谓的中间件就是有个next(),(req,res,next)

image.png

中间件的本质就是function,但是中间件函数的参数列表中必须包含next()

中间件的初体验

定义多个全局中间件

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

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

// 定义第一个全局中间件
app.use((req, res, next) => {
  console.log('调用了第1个全局中间件')
  next()
})
// 定义第二个全局中间件
app.use((req, res, next) => {
  console.log('调用了第2个全局中间件')
  next()
})

// 定义一个路由
app.get('/user', (req, res) => {
  res.send('User page.')
})

app.listen(80, () => {
  console.log('http://127.0.0.1')
})
定义多个局部中间件

全局与局部的区别就是有没有使用app.use

image.png
这是看似没有使用app.use,但是使用了app.use

// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()

// 1. 定义中间件函数
const mw1 = (req, res, next) => {
  console.log('调用了第一个局部生效的中间件')
  next()
}

const mw2 = (req, res, next) => {
  console.log('调用了第二个局部生效的中间件')
  next()
}

// 2. 创建路由
app.get('/', [mw1, mw2], (req, res) => {
  res.send('Home page.')
})
app.get('/user', (req, res) => {
  res.send('User page.')
})

// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})
中间件的注意事项

image.png

中间件的分类

基本的五类中间件

image.png

  1. 应用级别的中间件(绑定到app实例上的中间件)

image.png
2. 路由级别的中间件

用法和应用级别的中间件没有区别,但是绑定在router上

image.png
3. 错误级别的中间件

用来捕获整个项目中发生的错误,函数中必须有四个参数,错误级别的中间件放到所有路由之后

关于错误中间件的位置问题

在 Express 中间件的顺序很重要。对于错误处理中间件,注册顺序确实需要在路由之后,以便正确捕获整个应用程序的错误。

Express 中间件按照注册的顺序依次执行,因此如果将错误处理中间件放在路由之前,它可能无法捕获路由处理器中的错误,从而无法执行适当的错误处理。

所以,确保错误处理中间件在路由之后注册,以便它可以捕获到路由处理器中抛出的错误,并进行相应的处理。

image.png

  1. express内置的中间件

image.png

// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()

// 注意:除了错误级别的中间件,其他的中间件,必须在路由之前进行配置
// 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据
app.use(express.json())
// 通过 express.urlencoded() 这个中间件,来解析 表单中的 url-encoded 格式的数据
app.use(express.urlencoded({ extended: false }))

app.post('/user', (req, res) => {
  // 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
  // 默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined
  console.log(req.body)
  res.send('ok')
})

app.post('/book', (req, res) => {
  // 在服务器端,可以通过 req,body 来获取 JSON 格式的表单数据和 url-encoded 格式的数据
  console.log(req.body)
  res.send('ok')
})

// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})
  1. 第三方的中间件

image.png

//这里是用了第三方中间件来引用内置中间件,有点没看懂
// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()

// 1. 导入解析表单数据的中间件 body-parser
const parser = require('body-parser')
// 2. 使用 app.use() 注册中间件
app.use(parser.urlencoded({ extended: false }))
// app.use(express.urlencoded({ extended: false }))

app.post('/user', (req, res) => {
  // 如果没有配置任何解析表单数据的中间件,则 req.body 默认等于 undefined
  console.log(req.body)
  res.send('ok')
})

// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})

自定义中间件

🔴看图片复习

image.png

  1. 定义中间件:app.use定义中间件
  2. 监听data事件:
    data不是一次性发送所有数据的,而是一部分一部分发送的,发送完之后通过end事件表示数据发完了
let str = ''
req.on('data',(chunk)=>{
//监听data事件
str += chunk
}) 
  1. 监听end事件
req.on('end',()=>{
//end
console.log(str)
}) 
  1. 通过querystring解析请求体数据:

image.png

Q:什么叫做把查询字符串解析为对象格式,请给我一个例子
A:将查询字符串解析为对象格式意味着将 URL 查询参数字符串转换为 JavaScript 对象。在 Node.js 中,可以使用内置的 >querystring 模块的 parse 方法来实现这一功能。以下是一个例子:

假设有这样一个查询字符串:name=John&age=30&city=NewYork

使用 querystring 模块的 parse 方法将其解析为对象格式:

const qs = require('querystring');

const queryString = 'name=John&age=30&city=NewYork';
const parsedQuery = qs.parse(queryString);

console.log(parsedQuery);

输出结果会是一个包含解析后键值对的对象:

{
name: 'John',
age: '30',
  city: 'NewYork'
  }

这样就将查询字符串解析为了对象格式,可以通过对象的键来获取相应的值,使其更易于在代码中进行处理和操作。
ps:有可能连字符并不是&,可以通过parse的第二个参数指定连字符

  1. 将解析出来的数据挂载为body

image.png
完整代码:

// 导入 express 模块
const express = require('express')
// 创建 express 的服务器实例
const app = express()
// 导入 Node.js 内置的 querystring 模块
const qs = require('querystring')

// 这是解析表单数据的中间件
app.use((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)
    // TODO: 把字符串格式的请求体数据,解析成对象格式
    const body = qs.parse(str)
    req.body = body
    next()
  })
})

app.post('/user', (req, res) => {
  res.send(req.body)
})

// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(80, function () {
  console.log('Express server running at http://127.0.0.1')
})
  1. 将中间件封装为模块

image.png

我认为所谓的中间件模块就像函数一样,不过是多了一个next,中间件模块可以走的js普通模块同样可以做,只不过是中间件一般只用来处理请求和响应的中间环节。

使用express写接口

创建api路由模块

image.png

关于api 的探讨

api的本质是提供接口来利用其他软件系统或服务的功能,而不需要了解其内部实现细节。

在web中api可以只是一个web路径

Q: 什么是api

API(应用程序编程接口)是一组定义了不同软件组件之间交互的规则集合。它允许不同的软件系统或组件之间相互通信、交换数据或执行操作。API 可以在不同的软件层级之间提供通信和交互的桥梁,例如:

  1. Web API: 这是最常见的 API 类型之一,用于 Web 开发。Web API 允许不同的网络服务、应用程序或系统之间共享数据和功能。例如,通过 HTTP 请求和响应来访问的 RESTful API 或 GraphQL API。

  2. 库级别的 API: 编程语言中的库提供了一组函数和方法,这些函数和方法定义了程序员可以使用的特定功能。这些也是 API 的一种形式,允许开发者与库中的功能进行交互。

  3. 操作系统级别的 API: 操作系统提供了一系列函数和方法,允许应用程序与硬件和操作系统交互。这些 API 允许应用程序访问文件系统、网络功能、设备驱动程序等。

API 可以采用不同的形式,例如 RESTful API、SOAP API、WebSocket API 等,它们可能使用不同的协议、数据格式和通信方式来定义交互规则。开发者可以通过使用 API 提供的接口来利用其他软件系统或服务的功能,而不需要了解其内部实现细节。

Q: 我可以把api理解为一种web路径吗?

API 可以通过 Web 路径来暴露和访问,但 API 并不仅限于 Web 路径。API 更广义上指的是应用程序编程接口,它是一组定义了软件组件之间交互规则的约定集合。

在 Web 开发中,常见的是通过 HTTP 协议暴露 API,这些 API 通常会使用特定的路径和端点来与客户端进行通信。这些路径可以被视为用于访问和使用特定功能或数据的端点。例如:

  • RESTful API 路径:/users/products/orders 等路径可能代表着与用户、产品或订单相关的 API 端点。
  • GraphQL API 路径: GraphQL API 通常只有一个端点,例如 /graphql,通过该端点发送 GraphQL 查询。

这些路径代表着可以通过 HTTP 请求访问的特定功能或数据,但需要注意的是,API 并不仅限于 Web 路径。它还包括定义了软件组件之间如何通信、交换数据和执行操作的规则、协议和约定,这些规则可能不仅仅限于 Web 路径,也可以包括其他类型的接口和通信方式。

Q: 如何使用api,给我一个示例

当涉及到使用 API 时,你可以考虑以下情景:访问一个远程服务器上的数据或服务。比如,你想要访问一个天气预报的 API 来获取当前天气信息。以下是一个使用 Node.js 的示例,通过一个天气预报 API 获取天气信息的例子:

首先,你需要安装一个用于发起 HTTP 请求的包,比如 axios,你可以通过 npm 安装它:

npm install axios

接下来,这是一个简单的示例代码,使用 axios 库从一个天气预报 API 获取天气信息:

const axios = require('axios');

// 定义 API 的 URL 和相关参数
const API_KEY = 'YOUR_API_KEY'; // 替换为你的 API 密钥
const city = 'New York'; // 要获取天气信息的城市
const apiUrl = `http://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${API_KEY}`;

// 发起 GET 请求获取天气信息
axios.get(apiUrl)
  .then(response => {
    // 请求成功,处理获取到的天气数据
    const weatherData = response.data;
    console.log('Weather Data:', weatherData);
    // 在这里你可以对数据进行处理和使用
  })
  .catch(error => {
    // 请求出错,处理错误情况
    console.error('Error fetching weather data:', error);
  });

在这个示例中,我们使用了 axios 库来发起 HTTP GET 请求,从一个天气预报 API 获取天气信息。你需要将 API_KEY 替换为你在天气预报服务上获取的实际 API 密钥,并且指定要查询的城市。收到响应后,你可以处理并使用返回的天气数据。

这只是一个简单的例子,实际中使用 API 可能需要根据所用 API 的要求来配置参数、处理返回数据等。

编写get接口

image.png



apiRouter.get('/get', (req, res) => {
// 1,获取到客户端通过查询字符串,发送到服务器的数据2
const query = req.query
// 2.调用 res.send() 方法,把数据响应给客户端
res.send({
status: 0,
msg:"get请求成功",
data:query
})
})

这个代码的作用在于将发送的get的url中的查询参数作为数据返回给客户端

query会将查询参数变成对象的形式:

在 Express 中,req.query 是一个对象,用于存储从 URL 查询字符串解析出来的键值对。Express 在接收到 GET 请求时,会自动解析 URL 中的查询参数,并将其转换成一个对象形式,存储在 req.query 中,方便你在服务器端代码中访问和操作这些参数。

当你发送一个 GET 请求,比如 GET http://example.com/get?name=John&age=30,Express 会将查询字符串解析成如下格式的对象:

req.query = {
  name: 'John',
  age: '30'
}

所以,当你使用 req.query 访问查询参数时,它会以对象的形式返回解析后的键值对。这样你就可以在服务器端轻松地获取和处理客户端传递过来的查询参数。

编写post接口

image.png

什么是跨域请求:

跨域请求指的是在浏览器端发起的请求,其目标资源并不属于当前页面所在的域(域名、端口、协议组合)。当浏览器尝试在一个源(源指由协议、主机和端口组成的 URL)中加载来自另一个源的资源时,就会产生跨域请求。

源的概念

同源策略规定,如果两个 URL 具有相同的协议、主机和端口号,则它们属于相同的源。例如:

  • URL https://www.example.com/page1https://www.example.com/page2 是同源的,因为它们具有相同的协议(https)、主机名(www.example.com)和端口号(默认的(-vt8hueo3ch28pbijkk0cqfyc/) HTTPS 端口 443)。
  • URL https://www.example.com/page1https://api.example.com/data 不是同源的,因为它们的主机名不同。

同源策略的重要性在于它限制了一个源(页面)加载或操作另一个源的资源。具体来说:

关于跨域请求的理解:

Q: 我可以理解为我在csdn的网页中加载存储在知乎服务器上的图片的url吗

A: 对的,如果你在 CSDN 的网页中想要显示存储在知乎服务器上的图片,这就涉及到在一个网站(CSDN)中加载另一个网站(知乎)的资源(图片)。这种情况下,如果 CSDN 网页中使用 <img> 标签或者其他方式加载知乎服务器上的图片资源,就会产生跨域请求。

根据浏览器的同源策略,当你在 CSDN 页面中加载知乎服务器上的图片时,浏览器会认为这是一个跨域请求,因为两者的域名不同。这通常会导致图片加载失败,因为默认情况下浏览器会阻止跨域资源的加载。

要解决这个问题,通常可以通过以下方式之一来处理:

  • CORS(跨域资源共享): 知乎服务器可以配置允许来自 CSDN 网页的跨域请求访问其图片资源。
  • 代理服务器: 在 CSDN 服务器端设置代理,将对知乎图片资源的请求转发,让服务器去请求资源,然后再将资源返回给客户端。这样避免了在浏览器中直接请求跨域资源。
  • 下载并上传: 将知乎的图片下载到 CSDN 的服务器上,然后通过 CSDN 的域名来访问这些图片,避免了跨域问题。

CORS跨域资源共享

image.png

image.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值