Node.js常用知识

1、什么是 Node.js

【】Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。浏览器是 js 的前端运行环境,node.js 是 js 的后端运行环境。他们都有 V8 引擎,有各自的内置 API

2、fs 文件系统模块

【】fs 模块是 Node.js 官方提供的、用来操作文件的模块

【】fs.readFile() 方法,用来读取指定文件中的内容

【】fs.writeFile() 方法,用来向指定的文件中写入内容

【】 fs.writeFile() 方法只能用来创建文件,不能用来创建路径; 重复调用 fs.writeFile() 写入同一个文件,新写入的内容会覆盖之前的旧内容

// 1. 导入 fs 模块,来操作文件
const fs = require('fs')
fs.readFile(path[, options], (err, dataStr) => {})
fs.writeFile(path, data[, options], err => {})
3、path 路径模块

【】path.join() 方法,用来将多个路径片段拼接成一个完整的路径字符串

【】path.basename() 方法,用来从路径字符串中,将文件名解析出来

【】 path.extname() 方法,可以获取路径中的扩展名部分

const path = require('path')
const pathStr = path.join(__dirname, './files/1.txt')
const name = path.basename('/index.html')		//index.html
const nameWithoutExt = path.basename('/index.html', '.html')	//index
const fext = path.extname('/index.html')		//.html
4、http 模块

【】http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块

// 1. 导入 http 模块
const http = require('http')
// 2. 创建 web 服务器实例
const server = http.createServer()
// 3. 为服务器实例绑定 request 事件,监听客户端的请求
server.on('request', function (req, res) {
  const str = `您请求的 URL 地址是 ${req.url},请求的 method 类型为 ${req.method}`
  // 调用 res.setHeader() 方法,设置 Content-Type 响应头,解决中文乱码的问题
  res.setHeader('Content-Type', 'text/html; charset=utf-8')
  // 调用 res.end() 方法,向客户端响应一些内容
  res.end(str)
})
// 4. 启动服务器
server.listen(8080, function () {  
  console.log('server running at http://127.0.0.1:8080')
})
5、Node.js 中的模块化

【】分类:内置模块、自定义模块、第三方模块

【】require() 方法加载模块,加载模块时,会执行模块中的代码

const path = require("path")
const custom = require("./custom.js")	//.js 可以省略
const moment = require("moment")

【】模块作用域:和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问

【】在每个 .js 自定义模块中都有一个 module 对象,它里面存储了和当前模块有关的信息。在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用。外界用 require() 方法导入自定义模块时,得到的就是 module.exports 所指向的对象

【】Node 提供了 exports 对象。默认情况下,exports 和 module.exports 指向同一个对象。最终共享的结果,还是以 module.exports 指向的对象为准

const username = 'zs'

module.exports.username = username
exports.age = 20
exports.sayHello = function() {
  console.log('大家好!')
}
// { username: 'zs', age: 20, sayHello: [Function (anonymous)] }

【】Node.js 遵循了 CommonJS 模块化规范,CommonJS 规定了模块的特性和各模块之间如何相互依赖

【】模块优先从缓存中加载,内置模块的优先级最高

6、npm 与包

【】包管理配置文件 package.json ,使用 npm init -y 进行创建

npm install xxx		//下载包到 dependencies 节点(开发和线上都要用到)
npm i xxx
npm install xxx@2.2.2
npm uninstall xx
npm install xxx -D		//下载到 devDependencies 节点(开发中用到,线上不用)
npm install xxx --save-dev
npm config get registry		//查看下包镜像源
npm config set registry=https://registry.npm.taobao.org/
npm i xxx -g	//全局安装

【】npm i nrm -g 下载 nrm 工具,用老切换下包的镜像源

npm i nrm -g
nrm ls
nrm use taobao

【】包的规范:

  • 包必须以单独的目录而存在
  • 包的顶级目录下要必须包含 package.json 这个包管理配置文件
  • package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口
7、开发自己的包

【】包的基本结构(先创建一个根文件夹):

  • package.json (包管理配置文件)
  • index.js (包的入口文件)
  • README.md (包的说明文档)

【】package.json 文件内容:

{
  "name": "itheima-tools",
  "version": "1.1.0",
  "main": "index.js",
  "description": "提供了格式化时间、HTMLEscape相关的功能",
  "keywords": [
    "itheima",
    "dateFormat",
    "escape"
  ],
  "license": "ISC"
}

【】发布自己的包:

  • 注册 npm 账号,在终端执行 npm login 命令登录
  • 切换到包的根目录使用 npm publish 发布
  • 运行 npm unpublish 包名 --force 命令,即可从 npm 删除已发布的包
8、Express 使用

【】Express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架,是专门用来创建 Web 服务器的。基于内置模块 http 进一步封装出来的

【】Express 能快速创建 Web 网站服务器货或 API 接口服务器,使用 npm i express 安装

// 1. 导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()

// 4. 监听客户端的 GET 和 POST 请求,并向客户端响应具体的内容
app.get('/user', (req, res) => {
  res.send({ name: 'zs', age: 20, gender: '男' })
})
app.post('/user', (req, res) => {
  res.send('请求成功')
})
app.get('/', (req, res) => {
  // 通过 req.query 可以获取到客户端发送过来的 查询参数
  // 注意:默认情况下,req.query 是一个空对象
  console.log(req.query)
  res.send(req.query)
})
// 注意:这里的 :id 是一个动态的参数
app.get('/user/:ids/:username', (req, res) => {
  // req.params 是动态匹配到的 URL 参数,默认也是一个空对象
  console.log(req.params)
  res.send(req.params)
})

// 3. 启动 web 服务器
app.listen(80, () => {
  console.log('express server running at http://127.0.0.1')
})

【】托管静态资源

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

// 在这里,调用 express.static() 方法,快速的对外提供静态资源
//如果希望在托管的静态资源访问路径之前,挂载路径前缀,则可以使用如下的方式
//访问静态资源文件时,express.static() 函数会根据目录的添加顺序查找所需的文件
app.use('/files', express.static(path.join(__dirname, './files')))
app.use(express.static(path.join(__dirname, './clock')))

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

【】nodemon 工具能实现热更新, 使用 npm i nodemon -g 安装,使用 nodemon xxx.js 运行文件

9、Express 路由

【】路由指的是客户端的请求与服务器处理函数之间的映射关系,由三部分组成:请求类型、请求的URL地址、处理函数

// 挂载路由。 按照路由的顺序进行匹配
app.get('/', (req, res) => {
  res.send('hello world.')
})
app.post('/', (req, res) => {
  res.send('Post Request.')
})

【】模块化路由:创建路由模块对应的 .js 文件;调用 express.Router() 函数创建路由对象;向路由对象上挂载具体的路由;使用 module.exports 向外共享路由对象;使用 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
const express = require('express')
const app = express() 

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

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

app.listen(80, () => {
  console.log('http://127.0.0.1')
})
9、Express 中间件

【】Express 的中间件,本质上就是一个 function 处理函数。可以定义多个中间件,然后会按照中间件定义的先后顺序依次执行

// // 定义一个最简单的中间件函数
const mw = function (req, res, next) {
  console.log('这是最简单的中间件函数')
  // 把流转关系,转交给下一个中间件或路由
  next()
}
// // 将 mw 注册为全局生效的中间件
app.use(mw)
// 这是定义全局中间件的简化形式
app.use((req, res, next) => {
  console.log('这是最简单的中间件函数')
  next()
})

【】使用 app.use() 定义的是全局中间件,也可以定义局部中间件

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

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

【】中间件的五个注意事项:

  • 一定要在路由之前注册中间件(错误级中间件除外,要放在路由之后)
  • 客户端发送过来的请求,可以连续调用多个中间件进行处理
  • 执行完中间件的业务代码之后,不要忘记调用 next() 函数
  • 为了防止代码逻辑混乱,调用 next() 函数后不要再写额外的代码
  • 连续调用多个中间件时,多个中间件之间,共享 req 和 res 对象
10、中间件分类

【】应用级别的中间件

  • 通过 app.use() 或 app.get() 或 app.post() ,绑定到 app 实例上的中间件

【】路由级别的中间件

  • 绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别

【】错误级别的中间件

  • 有 4 个形参,形参顺序从前到后,分别是 (err, req, res, next)
app.get('/', (req, res) => {
  // 1.1 人为的制造错误
  throw new Error('服务器内部发生了错误!')
  res.send('Home page.')
})

// 2. 定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃
app.use((err, req, res, next) => {
  console.log('发生了错误!' + err.message)
  res.send('Error:' + err.message)
})

【】Express 内置的中间件

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

// 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
// 默认情况下,如果不配置解析表单数据的中间件,则 req.body 默认等于 undefined

【】第三方的中间件

11、自定义中间件

【】定义中间件

【】监听 req 的 data 事件

【】监听 req 的 end 事件

【】使用 querystring 模块解析请求体数据

【】将解析出来的数据对象挂载为 req.body

【】将自定义中间件封装为模块

// 导入 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()
  })
})
12、使用 Express 写接口

【】路由模块

const express = require('express')
const router = express.Router()

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

// 定义 POST 接口
router.post('/post', (req, res) => {
  // 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
  const body = req.body
  // 调用 res.send() 方法,向客户端响应结果
  res.send({
    status: 0,
    msg: 'POST 请求成功!',
    data: body,
  })
})

// 定义 DELETE 接口
router.delete('/delete', (req, res) => {
  res.send({
    status: 0,
    msg: 'DELETE请求成功',
  })
})

module.exports = router

【】主文件

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

// 配置解析表单数据的中间件


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

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

// 导入路由模块
const router = require('./16.apiRouter')
// 把路由模块,注册到 app 上
app.use('/api', router)

// 启动服务器
app.listen(80, () => {
  console.log('express server running at http://127.0.0.1')
})

【】测试文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js"></script>
  </head>
  <body>
    <button id="btnGET">GET</button>
    <button id="btnPOST">POST</button>
    <button id="btnDelete">DELETE</button>
    <button id="btnJSONP">JSONP</button>

    <script>
      $(function () {
        // 1. 测试GET接口
        $('#btnGET').on('click', function () {
          $.ajax({
            type: 'GET',
            url: 'http://127.0.0.1/api/get',
            data: { name: 'zs', age: 20 },
            success: function (res) {
              console.log(res)
            },
          })
        })
        // 2. 测试POST接口
        $('#btnPOST').on('click', function () {
          $.ajax({
            type: 'POST',
            url: 'http://127.0.0.1/api/post',
            data: { bookname: '水浒传', author: '施耐庵' },
            success: function (res) {
              console.log(res)
            },
          })
        })

        // 3. 为删除按钮绑定点击事件处理函数
        $('#btnDelete').on('click', function () {
          $.ajax({
            type: 'DELETE',
            url: 'http://127.0.0.1/api/delete',
            success: function (res) {
              console.log(res)
            },
          })
        })

        // 4. 为 JSONP 按钮绑定点击事件处理函数
        $('#btnJSONP').on('click', function () {
          $.ajax({
            type: 'GET',
            url: 'http://127.0.0.1/api/jsonp',
            dataType: 'jsonp',
            success: function (res) {
              console.log(res)
            },
          })
        })
      })
    </script>
  </body>
</html>
13、关于 CORS 跨域资源共享

【】CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口

【】CORS 响应头部 - Access-Control-Allow-Origin,参数值控制外域是否可访问,通配符允许来自任何域的请求

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

【】CORS 响应头部 - Access-Control-Allow-Headers:如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外
的请求头进行声明,否则这次请求会失败

【】CORS 响应头部 - Access-Control-Allow-Methods:默认情况下,CORS 仅支持客户端发起 GET、POST、HEAD 请求。通过 Access-Control-Alow-Methods
来指明实际请求所允许使用的 HTTP 方法

【】根据请求方式和请求头的不同,CORS请求的分类 :简单请求、预检请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值