Nodejs入门实战一篇精通

Nodejs

初始Node.js

Node.js® 是一个基于 Chrome V8 引擎 的JavaScript 运行时环境。

Node.js介绍

Node.js中的JavaScript环境

image-20220831161656095

Node.js可以做什么

Node.js作为一个JavaScript运行环境,仅仅提供了基础的功能和APi。然而,基于Node.js提供的这些基础功能,很多强大的工具和框架如雨后春笋,层出不穷,所以学习了Node.js,可以让前端程序员胜任更多的工作和岗位;

NodeJs学习路径

JavaScript 基础語法+Nodejs内置APl模块(s、path,http等)+第三方API模块(express.mysql 等)

NodeJs环境安装

区分LTS版本和Current 版本的不同

LTS为长期确定版,对于追求稳定性的企业级项目来说,推荐安装LTS版本的Node.j5.
Current为新特性类鲜版,对热表于装试新将性的用户来说,推荐安装Current 版本的Node js,但是,Current 版本中可
能存在隐副的Bug 呢安全性测同,因此不推荐在企业级项日中使用Current 版本的Node js。

fs文件系统模块

什么是fs文件系统模块

ts模诀是Node,js官方提供的、用来操作文件的横诀,它提供了一系列的方法和属性,用来满足用户对文件的操作需求。
例如:

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

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

  • 如果要在JavaScript代码中,使用fs模块来操作文件,则需要使用如下的方式先导入官:

    const fs = require('fs')
    
读取文件内容

fs.witefile()示例代码

参数1:文件路径

参数2:编码格式

参数3:回调函数

function readFile(path, options, callback)

const fs = require('fs');
fs.readFile('input.txt', 'utf-8', function (err, data) {
    if (err) {
        return console.log("读取文件失败:" + err.message);
    }
    console.log("读取文件成功:" + data);
})
文件写入内容

fs.witefile()示例代码

参数1:文件路径

参数2:写入内容

参数3:编码格式

参数4:回调函数

function writeFile(path, data, options, callback)

const fs = require('fs');
fs.writeFile('input.txt', "测试1", function (err) {
    if (err) {
        return console.log("文件写入内容失败!" + err.message)
    }
    console.log("文件写入成功");
})

模块-路径动态拼接问题

__dirname 获取当前文件所属目录

在使用横块操作文件时,如果提供的操作路径是以./../开头的相对路径时,很容易出现路径动拼接错误的问题。
原因:代码在运行的时候,会以执行node命令时所处的目录,动态拼接出被操作文件的完彪路径。

如果在input.txt上层目录执行node xxx/xxx.js 的话,如果出现错误读取不到文件,直接将./input.txt相对路径改为绝对路径读取。

const fs = require('fs');
fs.readFile('./input.txt', 'utf8', function (err, data) {
    if (err) {
        return console.log("读取文件失败" + err.message)
    }
    console.log("读取文件成功" + data);
})

//__dirname获取文件所处目录
const fs = require('fs');
fs.readFile(__dirname + '/input.txt', 'utf8', function (err, data) {
    if (err) {
        return console.log("读取文件失败" + err.message)
    }
    console.log("读取文件成功" + data);
    console.log(__dirname)
})

Path路径模块

什么是Path路径模块

path模块是Nodejs官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理

例如:
path.join()方法,用来将多个路径片段拼接成一个完整的路径字符串
path.basename()方法,用来从路径字符申中,将文件名解析出来
如果要在JavaScript代码中,使用path模块来处理路径,则需要使用如下的方式先导入它:

const path = require('path')
路径拼接

使用path.join0方法,可以把多个路径片段拼接为完格的路径字符串:

const pathStr = path.join('/a', '/b/c', '../', './d', 'e')
console.log(pathStr)//指出\a\b\d\e

const pathStr2 = path.join(__dirname, '/files/1.txt')

console.log(pathStr2)//物出 当前文件所处目录\files\1.txt
获取路径文件名

path.basename()的代码示例
使用path.basenam()方法,可以从一个文件路径中,获取到文件的名称部分

basename(path: string, ext?: string)

const path = require("path");

const fpath = '/a/b/c/index.html';
let filename = path.basename(fpath);
//分割指定内容
let newFileName = path.basename(filename,".html");

console.log(filename);//index.html
console.log(newFileName)//index
获取路径中扩展名

使用 path.extname0方法,可以获取路径中的扩展名部分,语法格式如下:

path.extname(path)

参数解读:

  • path必选参数,表示一个路径的字符串
  • 返回:返回得到的扩展名字符串
const path = require("path");

const pathStr = "/a/b/c/index.html";
let extname = path.extname(pathStr);
console.log(extname)//.html

http模块

什么是http模块

回顾:什么是客户端、什么是服务器?

在网络节点中,负责消费资源的电脑,叫做客户端;负责对外提供网络资源的电脑,叫做服务器。
http模块是Node.js官方提供的、用来创建 web 服务器的模块。通过http模块提供的http.createServer()方法,就能方便的把一台普通的电脑,变成一台Web服务器,从而对外提供Web资源服务。

如果要希望使用http模块创建Web服务器,则需要先导入它:

const http = require('http')
http模块作用

服务器和普通电脑的区别在于,服务器上安装了web服务器软件,例如:IIS、Apache等。通过安装这些服务器软件,就能把一台普通的电脑变成一台web服务器。

Node.js中,我们不需要使用IIS、Apache等这些第三方web服务器款件。因为我们可以基于Node.js提供的
http模块,通过几行简单的代码,就能轻松的手写一个服务器软件,从而对外提供web服务。

创建web服务器

①导入http模块
②创建 web 服务器实例
③为服务器实例绑定request事件,监听客户端的请求
④启动服务器

//导出http模块
const http = require('http');
//创建web服务器
const server = http.createServer();
//为服务器示例绑定request事件,监听客户端的请求
server.on('request', function (req, res) {
    console.log("调用了request方法")
})
//启动服务器
server.listen(8080, function () {
        console.log("访问http://127.0.0.1:8080 获取结果")
    }
)
request请求

获取request里面的数据和属性参数

//导出http模块
const http = require('http');
let server = http.createServer();
// req是请求对象,包含了与客户端的数据和属性
server.on('request', (req, res) => {
    const url = req.url;
    const method = req.method;
    const str = `url地址${url}, 方法是${method}`;
    console.log(req);
    console.log(str);
})

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

响应结束

res.end();

解决中文乱码,设置Header

res.setHeader('Content-Type', 'application/json');

res.setHeader('Content-Type', 'text/html;charset=utf-8');

//response响应对象
const http = require('http');
let server = http.createServer();
// req是请求对象,包含了与客户端的数据和属性
server.on('request', (req, res) => {
    const url = req.url;
    const method = req.method;
    const str = `url地址${url}, 方法是${method}`;
    res.setHeader('Content-Type', 'text/html;charset=utf-8');
    // res.setHeader('Content-Type', 'application/json');
    res.end(str)
})

server.listen(8080, () => {
    console.log('server running at http://127.0.0.1:8080');
})
根据不同URL相应不同内容
const http = require('http');
let server = http.createServer();

server.on('request', function (req, res) {
    //获取请求URL
    let url = req.url;
    let content = "<h1>404 Not found!</h1>";
    if (url === '/' || url === '/index.html') {
        content = '<h1>首页</h1>'
    } else if (url === '/about.html') {
        content = '<h1>关于页面</h1>'
    }
    res.setHeader('Content-Type', 'text/html; charset=UTF-8');
    res.end(content);
})

server.listen(8080, () => {
    console.log("启动成功访问http://127.0.0.1:8080")
})

模块化

能够说出模块化的好处
能够知道CommonJS规定了哪些内容
能够说出Node.js中模块的三大分类各自是什么
能够使用npm管理包
能够了解什么是规范的包结构
能够了解模块的加载机制

模块化概念

编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。

把代码进行模块化拆分的好处:

  • ①提高了代码的复用性
  • ②提高了代码的可维护性
  • ③可以实现按需加载

模块化规范就是对代码进行模块化的拆分与组合时,需要遵守的那些规则。
例如:

  • 使用什么样的语法格式来引用模块
  • 在模块中使用什么样的语法格式向外剔需成员
  • 模块化规范的好处:大家都遵守同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己。

模块的分类

Node.js中根据模块来源的不同,将模块分为了3大类,分别是:

  • 内置模块(内置模块是由 Node.js官方提供的,例如fs、path、http等)
  • 自定义横块(用户创建的每个js文件,都是自定义横块)
  • 第三方模块(由第三方开发出来的横块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下或)

加载模块

使用强大的require0方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用。例如:

//1.加载内置的fs模块
const fs = require('fs')
//2.加载用户的自定义模块
const custom = require('./custom.js')
//3.加载箱三方模块(关于第三方模块的下载和使用,会在后面的课程中进行专门的讲解)
const moment = require('moment')

注意:使用 require0方法加载其它模块时,会执行被加载模块中的代码。

//使用 require0方法加载其它模块时,会执行被加载模块中的代码,在使用require0加载自定义模块可以省略.js后缀名`
const test = require('E:\\work2\\node-learning\\node基础\\01.使用readFile读取文件.js');
console.log(test)

//{}
//读取文件成功:测试1

模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。

防止了全局变量污染的问题,在模块内定义的成员不能被外部访问

image-20220902101110268

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

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

Module {
  id: '.',
  path: 'E:\\work2\\node-learning\\模块化',
  exports: {},
  parent: null,
  filename: 'E:\\work2\\node-learning\\模块化\\04.module对象.js',
  loaded: false,
  children: [],
  paths: [
    'E:\\work2\\node-learning\\模块化\\node_modules',
    'E:\\work2\\node-learning\\node_modules',
    'E:\\work2\\node_modules',
    'E:\\node_modules'
  ]
}
module.exports 对象

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

module.exports.username = ‘张三’ exports.username = '张三’指向的是同一个对象,一种简写方式

image-20220902102458404

共享成员注意点

使用requireo方法导入模块时,导入的结果,永远以module.exports 指向的对象为准

image-20220902104149894

//	{ nikeName: '李四', test: [Function: test], aaa2: 25 }

CommonJS 模块化规范

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

模块的加载机制

优先从缓存中加载

模块在第一次加载后会被缓存。这也意味看多次调用require()不会导致模块的代码被执行多次。
注意:不论是内置模块、用户自定义模块、还是第三方模块,它们都会优先从缓存中加载,从而提高模块的加载效率。

内置模块加载机制

内置模块是由Node.js官方提供的模块,内置模块的加戦优先级最高。

例如,require(‘fs’)始终返回内置的fs模块,即使在node_modules目录下有名字相同的包也叫做fs.而不是加载第三方的

自定义模块加载机制

使用 require()加载自定义模块时,必须指定以./../开头的路径标识符。在加载自定义模块时,如果没有指定./../这样的路径标识符,则node会把它当作内置模块第三方模块进行加载。

同时,在使用requireO导入自定义模块时,如果省略了文件的扩展名,则Node.js会按顺序分别尝试加载以下的文件:

①按照确切的文件名进行加载
②补全js扩展名进行加载
③补全json扩展名进行加载
④补全.node扩展名进行加载
⑤加载失效,终端报错

第三方模块的加载机制

如果传递给requir()的模块标识符不是一个内置模块,也没有以‘./’‘../’ 开头,则Node.js会从当前模块的父目录开始,尝试从/node_modules 文件夹中加载第三方模块。如果没有找到对应的第三方模块,则移动到再上一层父目录中,进行加就,直到文件系统的根目录。

例如,假设在‘C:AUsersVitheima\project\foo.js’文件里调用了require(‘tools’),则Node.js会按以下顺序查找:
C:\Users\itheima\project\node_modules\tools
C:\Users\itheima\node_modules\tools
C:\Users\node_modules\tools
C:\node_modules\tools

express

什么是express

官方给出的概念:Express是基于Node.js平台,快速、开放、极简的Web开发框架。

通俗的理解:Express的作用和Node.js内置的http模块类似,是专门用来创建Web服务器的。

Express的本质:就是一个npm上的第三方包,提供了快速创建Web服务器的便捷方法。

express能做什么

对于前端程序员来说,最常见的两种服务器,分别是:

  • Web 网站服务器:专门对外提供Web 网页资源的服务器。
  • API接口服务器:专门对外提供API接口的服务器。

使用Express,我们可以方便、快速的创建Web网站的服务器或APl接口的服务器。

express基本使用

安装依赖

node i express@4.17.1
//引入express模块
let express = require('express');
//创建服务器
let app = express();
//监听端口
app.listen(8080, () => {
    console.log('express server running at http://localhost:8080');
})
express GET\POST
//引入express
let express = require('express');
//创建服务器
let app = express();

//测试GET请求,获取参数
app.get('/user/:id/:name', function (req, res) {
    let arrayData = [];
    //获取动态参数,路径参数id,name
    let params = req.params;
    //获取query参数,查询条件
    let query = req.query;

    arrayData.push(params);
    arrayData.push(query)
    res.send(arrayData)
})

//测试POST请求获取参数
app.post('/user', (req, res) => {
    res.send("请求成功")
})

//启动服务
app.listen(8080, () => {
    console.log("测试GET POST请求,http://localhost:8080");
})
托管静态资源
  • 通过 express.static() 方法可创建静态资源服务器,向外开放访问静态资源。
  • Express 在指定的静态目录中查找文件,并对外提供资源的访问路径,存放静态文件的目录名不会出现在 URL 中
  • 访问静态资源时,会根据托管顺序查找文件
  • 可为静态资源访问路径添加前缀
  • 托管多个静态文件目录,引入多个按照引入顺序加载
const express = require('express');
const app = express();

//引入多个按照顺序加载,先去public找public没有然后去files文件夹找,http://localhost:8080/index.html
app.use(express.static("../public"))
app.use(express.static("../files"))

//指定访问前缀,指定访问前缀在访问静态文件需要添加上前缀http://localhost:8080/public/index.html
// app.use("/public", express.static("../public"))

app.listen(8080, () => {
    console.log("访问静态文件http://localhost:8080")
})

nodemon

在编写调试Node.js项目的时候,如果修改了项目的代码,则需要频繁的手动close掉,然后再重新启动,非常繁琐。现在,我们可以使用nodemon(https://www.npmjs.com/package/nodemon)这个工具,它能够监听项目文件的变动,当代码被修改后,nodemon会自动帮我们重启项目,极大方便了开发和调试。

npm i -g nodemon
使用nodemon

当基于Node.js编写了一个网站应用的时候,传统的方式,是运行node app.js命令,来启动项目。这样做的坏处是代码被修改之后,需要手动重启项目。
现在,我们可以将node命令替换为nodemon命令,使用nodemon app.js来启动项目。这样做的好处是:代码被修改之后,会被nodemon监听到,从而实现自动重启项目的效果。

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

express路由

引用路由
  • 定义路由模块
//1、导入express
const express = require('express');
//2、创建路由对象
const route = express.Router();

//添加get请求
route.get('/user/list', (req, res) => {
    console.log("GET请求参数", req.query);
    res.send(req.query)
})

//添加post请求
route.post('/user/add', (req, res) => {
    console.log("POST请求参数", req.body);
    res.send(req.body)
})

//导出路由对象
module.exports = route;
  • 调用路由
const express = require('express');
//引入Router自定义模块
const router = require('./04.路由简单用法Router');
//创建服务器
const app = express();
/**
 * app.use()就是来注册全局中间件的
 * 加载router模块,添加固定前缀api
 * GET  http://localhost:8080/api/user/list?aaa=123
 * POST http://localhost:8080/api/user/add
 */
app.use('/api', router);
//启动服务
app.listen(8080, () => {
    console.log("测试引用路由,http://localhost:8080")
})

express中间件

  • 中间件是指流程的中间处理环节
  • 服务器收到请求后,可先调用中间件进行预处理
  • 中间件是一个函数,包含 req, res, next 三个参数,next() 参数把流转关系交给下一个中间件或路由

中间件注意事项;

  • 在注册路由之前注册中间件(错误级别中间件除外)
  • 中间件可连续调用多个
  • 别忘记调用 next() 函数
  • next() 函数后别写代码
  • 多个中间件共享 reqres对象
全局中间件
  • 通过 app.use() 定义的中间件为全局中间件
//1、引用express模块
const express = require('express');
//2、创建服务
const app = express();

//3、创建中间件函数
const mw = function (req, res, next) {
    console.log("调用了中间件方法");
    //最后必须要执行的方法,下一步
    next();
}

//4、注册全局中间件
app.use(mw);

//创建中间件函数,并注册简化写法
// app.use(function (req, res, next) {
//     console.log("调用了中间件方法");
//     //最后必须要执行的方法,下一步
//     next();
// });

//5、挂载方法
//挂载GET http://127.0.0.1:8080/
app.get('/', (req, res) => {
    console.log("调用了/ 路由方法");
    res.send("Home Page···")
})
//挂载GET http://127.0.0.1:8080/user
app.get('/user', function (req, res) {
    console.log("调用了user 路由方法");
    res.send('User Page···')
})

//6、启动服务
app.listen(8080, () => {
    console.log("启动服务器http://127.0.0.1:8080");
})

//调用了中间件方法
//调用了/ 路由方法
多个全局中间件

可以使用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('/', (req, res) => {
    console.log("调用get方法")
    res.send("成功!")
})


app.listen(8080, () => {
    console.log("服务启动成功,http://localhost:8080")
})
//http://localhost:8080/
//第一个中间件函数
//第二个中间件函数
//调用get方法
局部中间件

不使用app.use()定义的中间件,叫做局部生效的中间件,示例代码如下:

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

const mw = function (req, res, next) {
    console.log("局部生效中间件函数1")
    req.startTime = new Date();
    //必须
    next()
}

const mw1 = function (req, res, next) {
    console.log("局部生效中间件函数2")
    req.startTime = new Date();
    //必须
    next()
}

app.get('/user', (req, res) => {
    console.log("调用user方法", req.startTime);
    res.send(req.startTime)
})
//设置局部生效中间件
app.get('/', mw, (req, res) => {
    console.log("调用/方法", req.startTime);
    res.send(req.startTime)
})

//设置多个局部生效中间件
app.get('/user/list1', mw, mw1, (req, res) => {
    console.log("调用/方法", req.startTime);
    res.send(req.startTime)
})
app.get('/user/list2', [mw, mw1], (req, res) => {
    console.log("调用/方法", req.startTime);
    res.send(req.startTime)
})


app.listen(8080, () => {
    console.log("服务启动http://127.0.0.1:8080")
})
中间件分类
  1. 应用级别中间件

    • 通过app.use()app.get()app.post(),绑定到app实例上的中间件,叫做应用级别的中间件,代码示例如下:

    • //应用级别中间件(全局中间件)
      app.use(function (req, res, next) {
          console.log("全局中间件")
          next()
      })
      
      
      //应用级别中间件(局部中间件)
      const mw = function (req, res, next) {
          console.log("局部生效中间件函数")
          req.startTime = new Date();
          //必须
          next()
      }
      app.get('/', mw, (req, res) => {
          console.log("调用/方法", req.startTime);
          res.send(req.startTime)
      })
      
  2. 路由级别中间件

    • 绑定到express.Route()实例上的中间件,叫做路由级别的中间件。它的用法和应用级别中间件没有任何区别。只不过,应用级别中间件是绑定到app实例上,路由级别中间件绑定到router实例上,代码示例如下:

    • const express = require('express');
      const router = express.Router();
      
      //设置Router中间件
      router.use(function (req, res, next) {
          console.log("router级别中间件")
          next();
      })
      
      //router绑定方法
      router.get('/user', function (req, res) {
          console.log("调用routerGET方法")
          res.send("调用routerGET方法")
      })
      
      //向外暴露
      module.exports = router
      
      
    • const express = require('express');
      //引入05.router级别中间件自定义模块
      const routerTest = require('./05.router级别中间件');
      //创建服务器
      let app = express();
      
      //设置routerTest中间件
      app.use(routerTest);
      
      //服务启动GET http://localhost:8080/user
      app.listen(8080, () => {
          console.log("服务启动成功,http://localhost:8080")
      })
      
      
      
  3. 错误级别中间件

    • 错误级别中间件的作用:专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题。

    • 格式:错误级别中间件的function 处理函数中,必须有4个形参,形参顺序从前到后,分别是(err,req,res,next)

    • 错误级别的中间件,放到所有路由请求之后

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

    自Express 4.16.0版本开始,Express内置了3个常用的中间件,极大的提高了Express项目的开发效率和体验:
    express.static快速托管静态资源的内置中间件,例如:HTML文件、图片、CSS样式等(无兼容性)
    express.json解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)

    express.urlencoded解析URL-encoded格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)

    • //添加router.use(express.json()) json解析中间件,post请求req.body JSON参数可以正常取到,否则req.body=undefined
      app.use(express.json())
      //Body参数,x-www-form-urlencoded参数
      app.use(express.urlencoded({ extended: false }))
      
      
      --------------------------------------------------------------------
      
      const express = require('express');
      const app = express();
      //Body参数,json参数
      app.use(express.json())
      //Body参数,x-www-form-urlencoded参数
      app.use(express.urlencoded({ extended: false }))
      
      app.post('/user/add', (req, res) => {
          console.log(req.body);
          res.send(req.body);
      })
      //启动服务
      app.listen(8080, () => {
          console.log("express内置中间件启动成功http://127.0.0.1:8080")
      })
      
中间件的作用

多个中间件之间,共享同一份reqres,基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义属性方法,供下游的中间件或路由进行使用。

image-20220905145411180

// 引入express
const express = require('express');
//创建服务器
let app = express();
//定义中间件函数
const mw = function (req, res, next) {
    console.log("进入了中间件函数");
    //req设置自定义参数
    req.startTime = new Date();
    //调用next方法
    next();
}

//注册中间件
app.use(mw)

//挂载方法
app.get('/', (req, res) => {
    console.log("获取中间件设置的自定义参数", req.startTime)
    res.send(req.startTime)
})

//启动服务
app.listen(8080, () => {
    console.log("服务启动,http://127.0.0.1:8080")
})
自定义中间件
  • 暴露中间件模块
//引入express模块
const express = require('express');
const app = express();
//引入querystring模块
const qs = require('querystring');

app.use(function (req, res, next) {
    //定义变量
    let str = '';

    //开始
    req.on('data', (chunk) => {
        str += chunk;
    })

    //结束
    req.on('end', () => {
        //将字符串转对象
        const parsedUrlQuery = qs.parse(str);
        //对象设置body参数
        req.body = parsedUrlQuery

        next();
    })
})

//挂载请求
app.post('/user/add', (req, res) => {
    res.send(req.body);
})


//暴露外部模块
module.exports = app

  • 启动服务
const express = require('express');
//引入自定义中间件
const zidingyi = require('./09.自定义中间件01');
//获取服务器
const app = express();
//设置自定义中间件为全局中间件
app.use(zidingyi)
//启动服务
app.listen(8080, () => {
    console.log("自定义模块启动,http://localhost:8080")
})

express写接口例子

api路由接口文件

01.apiRouter.js

const express = require('express');
//1. 创建一个路由容器
const router = express.Router();

//2.编写接口
router.get('/get', function (req, res) {
    //获取req.query查询参数
    const query = req.query;
    res.send(
        {
            code: 200,
            message: 'GET查询成功',
            data: query
        }
    )
})

router.post('/post', function (req, res) {
    //获取body参数
    const body = req.body;
    res.send({
        code: 200,
        message: 'POST提交成功',
        data: body
    })
})


//3.路由外部暴露
module.exports = router
api服务模块
const express = require('express');
//1.创建服务器
const app = express();

//2.导入apiRouter路由模块
const router = require('./01.apiRouter')

//3.导入cors跨域模块
const cors = require('cors');


//4.注册JSON中间件、解析URL-encoded中间件 (内置中间件) \配置跨域中间件app.use(cors())
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use(cors())

//5.注册router中间件
app.use(router);

//6.启动服务
app.listen(8080, function () {
    console.log("api接口启动成功,http://localhost:8080")
})

CORS跨域资源共享

解决跨域问题

cors是Express的一个第三方中间件。通过安装和配置cors中间件,可以很方便地解决跨域问题。
使用步骤分为如下3步:

//1.安装cors模块
npm install cors

//2.导入cors模块
const cors = require('cors');

//3.注册cors模块
app.use(cors())
CORS
  • CORS(Cross-Origin Resource Sharing,跨域资源共享)解决跨域,是通过 HTTP 响应头决定浏览器是否阻止前端 JS 代码跨域获取资源
  • 浏览器的同源安全策略默认会阻止网页“跨域”获取资源。但如果接口服务器配置了 CORS 相关的 HTTP 响应头,就可解除浏览器端的跨域访问限制
  • CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了 CORS 的接口。
  • CORS 在浏览器中有兼容性。只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了 CORS 的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。
CORS 常见响应头
  • Access-Control-Allow-Origin:制定了允许访问资源的外域 URL
res.setHeader('Access-Control-Allow-Origin', 'http://bruceblog.io')
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 对额外的请求头进行声明,否则这次请求会失败!
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 方法
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, HEAD')
res.setHEader('Access-Control-Allow-Methods', '*')
CORS 请求分类
简单请求
  • 请求方式:GET、POST、HEAD 三者之一
  • HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值 application/x-www-formurlencoded、multipart/form-data、text/plain)
预检请求
  • 请求方式为 GET、POST、HEAD 之外的请求 Method 类型
  • 请求头中包含自定义头部字段
  • 向服务器发送了 application/json 格式的数据

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

、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)`

  • 如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!
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 方法
res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE, HEAD')
res.setHEader('Access-Control-Allow-Methods', '*')
CORS 请求分类
简单请求
  • 请求方式:GET、POST、HEAD 三者之一
  • HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值 application/x-www-formurlencoded、multipart/form-data、text/plain)
预检请求
  • 请求方式为 GET、POST、HEAD 之外的请求 Method 类型
  • 请求头中包含自定义头部字段
  • 向服务器发送了 application/json 格式的数据

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

最后

最后准备了一份资料分享给大家,获取链接:2022年Java开发全套学习资料

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冒险的梦想家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值