一般做企业网站需要什么,建网站的每年有费用,网站备案字号,wordpress 时光轴代码初识 Node.js 与内置模块
#xff08;初识#xff09; 1、知道什么是node.js 2、知道node.js可以做什么 3、node.js 中js的组成部分 #xff08;内置模块#xff09; 4、用 fs 模块读写操作文件 5、使用 path 模块处理路径 6、使用http 模块写一个基本的web服务器
初识 N…初识 Node.js 与内置模块
初识 1、知道什么是node.js 2、知道node.js可以做什么 3、node.js 中js的组成部分 内置模块 4、用 fs 模块读写操作文件 5、使用 path 模块处理路径 6、使用http 模块写一个基本的web服务器
初识 Node.js
回顾与思考
回忆浏览器中的 JavaScript 组成 为什么JavaScript可以在浏览器中被执行是因为浏览器中存在JavaScript解析引擎而不同的浏览器使用的解析引擎是不一样的 因此可以总结出 JavaScript 的运行环境就包括下面两个部分 由上述内容我们可以总结出两点
1、V8 引擎负责解析和执行 JavaScript 代码
2、内置 API 是由运行环境提供的特殊接口只能在所属的运行环境中被调用
那么 JavaScript 能否做后端开发呢 当然是没有问题的JavaScript 本身只是一门语言这门语言所编写出来的代码想要执行的话离不开运行时环境如果将 JavaScript 的代码放在浏览器里运行那么浏览器本身就是一个运行时环境此时 JavaScript 就可以用来做前端开发同时如果我们将 JavaScript 代码放在 Node.js 环境Node.js 也是一个 JavaScript 的运行时环境只不过是一个后端的运行时环境当中通过 Node.js 就可以让我们的 JavaScript 去做后端开发了。
Node.js 简介
先来看一段官方的介绍 为什么是基于 Chrome V8 呢之前说过因为它最牛逼。所以使用 V8 来做 Node.js 的引擎用以解析 JavaScript 的代码这样可以让 JavaScript 跑的更快。
所以我们的 Chrome 浏览器和 Node.js 用的是同一款 JavaScript 解析引擎即 V8
只不过 V8 用在不同的地方做的事情是不一样的在 Chrome 浏览器中用 V8 解析 JavaScript 做的是前端的开发而在 Node.js 中使用 V8 解析 JavaScript 则做的是后端开发仅此而已。
Node.js 的运行时环境 可以看见Node.js 为我们提供了后端开发所需要的所有模块的 API因此学习 Node.js 很大程度上就是学习怎么使用这些内置的后端开发的 API。
Node.js 可以做什么 一句话全栈
Node.js 怎么学 Node.js 环境的安装 官方网址Node.js 直接下载完成后双击安装即可一路按照默认的来就行。
检测安装是否成功打开 cmd 命令终端输入 node -v能正常显示版本号即正常 这样就安装完成了。
什么是终端 在 Node.js 环境中执行 JavaScript 代码
下面介绍的是比较朴素的方式因为现在都使用 IDE 了我用的是 WebStorm比较推荐IDE 的使用就不介绍了网上很多不再赘述。
就两步 先来写一个 1.js 文件 然后进入终端在当前文件目录的命令行下用 node 命令启动即可 这样就可以运行 JavaScript 代码啦。
有一种便捷打开命令行的方式即在我们的文件目录下按住 shift 后点击鼠标右键会有一个打开 PowerShell 的选项 点击它 可以看见这种方式更加的快捷那么 PowerShell 和我们之前的 CMD 方式有什么区别呢
CMD 方式是出现的比较早的一种方式是旧版本的 windows 里的终端后来 windows 做了升级改成了 PowerShell 也就是新版本的 CMD其实用哪个都行但是 PowerShell 的功能更加强大一些。
终端中常用的一些快捷键 使用WebStorm编写 Node.js 代码没有提示问题解决
参考这篇文章使用WebStorm编写 Node.js 代码没有提示问题解决
fs 文件系统模块
什么是 fs 文件系统模块 我们只需要知道在安装 Node.js 的时候这些模块就都被安装到电脑本地了即可然后需要用到哪个模块就使用 require 方法将其导入进来即可。
读取指定文件中的内容
fs.readFile() 的语法格式 示例代码如下
// 1、到入 fs 模块操作文件
const fs require(fs)//2、调用 fs.readFile() 方法读取文件
// 参数1、 读取文件的存放路径
// 参数2、 读取文件时候采用的编码格式一般默认指定 utf8
// 参数3、 回调函数拿到读取失败和成功的结果err dataStr
fs.readFile(./1.txt, utf8, function (err, dataStr){// 打印失败的结果// 如果读取成功则err 的值为null// 如果读取失败则 err 的值为错误对象dataStr 的值为 undefined// 因此可以通过判断 err 对象是否为 null来判断文件读取是否成功console.log(err)console.log(----------------)// 打印成功的结果// 如果读取成功那么dataStr就是从文件当中读取的值// 如果读取失败那么dataStr就是undefinedconsole.log(dataStr)
})运行结果如下 关于fs.readFile()第三个参数是回调函数的解释
fs.readFile(./1.txt, utf8, function (err, dataStr){console.log(err)console.log(----------------)console.log(dataStr)
})这段代码中的回调函数是作为 fs.readFile 方法的最后一个参数传递进去的。根据 Node.js 中的约定回调函数的第一个参数通常用于表示错误信息第二个参数则是成功时返回的数据或结果这是 fs.readFile() 函数的形式约定。
所以当你使用 fs.readFile 方法时如果文件读取成功Node.js 会将 err 参数置为 null而将文件内容作为 dataStr 参数传递给回调函数如果文件读取失败Node.js 会将 err 参数设置为相应的错误对象而 dataStr 则会是 undefined。
因此通过检查 err 参数是否为 null你可以轻松地判断文件读取是否成功。如果 err 为 null则表示读取成功可以在 dataStr 中访问文件内容如果 err 不为 null则表示读取失败dataStr 会是 undefined同时你可以查看 err 对象来了解具体的错误信息。
向指定的文件中写入内容
fs.writerFile的语法格式 示例代码如下
const fs require(fs)fs.writeFile(./2.txt, abcd, utf8, function (err){// 如果文件写入成功则 err 的值等于 null// 如果文件写入失败则 err 的值等于一个错误对象console.log(err)
})运行结果如下 因为运行成功因此 err 是 null 值。
fs 模块 - 路径动态拼接的问题 出现路径拼接错误的问题是因为提供了 ./ 或者 …/ 开头的相对路径。
如果要解决这个问题可以直接提供一个完整的文件存放路径即绝对路径即可。
但是这又会带来一种新的问题就是代码的移植性非常差不利于维护。
那么如何完美解决这个问题呢可以使用 Node.js 给我们提供的 __dirname 参数 测试也比较简单打印出来即可知道 __dirname 就是代表当前文件所处的目录因此不再赘述。
path 路径模块
什么是 path 路径模块 路径拼接
path.join() 的语法格式 代码示例如下
const path require(path)// 注意../ 会抵消前面的路径
const pathStr path.join(/a,/b/c,../,./d,e)console.log(pathStr) // 输出\a\b\d\e//今后凡是涉及到路径拼接的操作都要使用 path.join() 方法进行处理。
// 不要用 进行字符串拼接
const pathFile path.join(__dirname, /a/1.txt)console.log(pathFile)运行结果如下 获取路径中的文件名
path.basename() 的语法格式 示例代码
const path require(path)//定义文件的存放路径
const fpath /a/b/c/index.htmlconst fullName path.basename(fpath)
console.log(fullName) //输出index.htmlconst nameWithoutExt path.basename(fpath, .html)
console.log(nameWithoutExt) //输出index运行结果如下 获取路径中的文件扩展名
path.extname() 的语法格式 示例代码如下
const path require(path)//这是文件的存放路径
const fpath /a/b/c/index.htmlconst fext path.extname(fpath)console.log(fext)运行结果如下 关于 path 模块需要注意的两个小点 http 模块
什么是 http 模块 进一步理解 http 模块的作用 创建最基本的 web 服务器 上面的步骤细分下来其实就是下面这样
第一步导入 http 模块 第二步创建 web 服务器实例 第三步为服务器实例绑定 request 事件 第四步启动服务器 接下来我们来代码实操一下
//1、导入 http模块
const http require(http)
//2、创建 web 服务器实例
server http.createServer()
//3、为服务器实例绑定 request 事件监听客户端的请求
server.on(request, function (req, res){console.log(Someone visit our web server.)
})
//4、启动服务器
server.listen(80,function (){console.log(Server running at http://127.0.0.1)
})运行效果如下 可以发现当我们在浏览器访问该地址的时候我们的监听事件已经监听到了事件。
补充什么是箭头函数
这是 JavaScript 中的箭头函数语法。(){} 是一个简单的箭头函数它表示一个没有参数的函数并返回一个空对象即函数体内没有执行任何操作。箭头函数是 ES6ECMAScript 2015中引入的一种新的函数声明方式它可以更简洁地定义函数并且在一些情况下具有更清晰的语义。
req 请求对象 代码示例如下
const http require(http)
server http.createServer()
// req 是请求对象包含了与客户端相关的数据和属性
server.on(request, (req){// req.url 是客户端请求的 url 地址const url req.url//req.method 是客户端请求的 method 类型const method req.methodconst str Your request url is ${url}, and request method is ${method}console.log(str)
})server.listen(80,function (){console.log(Server running at http://127.0.0.1)
})运行效果如下 res 响应对象 示例代码如下
const http require(http)
server http.createServer()
// req 是请求对象包含了与客户端相关的数据和属性
server.on(request, (req, res){// req.url 是客户端请求的 url 地址const url req.url//req.method 是客户端请求的 method 类型const method req.methodconst str Your request url is ${url}, and request method is ${method}console.log(str)// 调用 res.end() 方法向客户端响应一些内容res.end(str)
})server.listen(80,function (){console.log(Server running at http://127.0.0.1)
})运行效果如下 解决中文乱码的问题 代码示例如下
const http require(http)
server http.createServer()
// req 是请求对象包含了与客户端相关的数据和属性
server.on(request, (req, res){// req.url 是客户端请求的 url 地址const url req.url//req.method 是客户端请求的 method 类型const method req.methodconst str 你的请求路径是 ${url}, 请求方法是 ${method}console.log(str)// 发送数据前设置响应头设置编码方式res.setHeader(Content-Type, text/html; charsetutf-8)// 调用 res.end() 方法向客户端响应一些内容res.end(str)
})server.listen(80,function (){console.log(Server running at http://127.0.0.1)
})运行效果如下 根据不同的 url 响应不同的 html 内容 动态响应内容的代码示例
const http require(http)server http.createServer()// req 是请求对象包含了与客户端相关的数据和属性
server.on(request, (req, res){//1、获取请求的 url 地址const url req.url//2、设置默认的响应内容为 404 Not Foundlet content 404 Not Found//3、判断用户请求的是否为 / 或者 /index.html 页面//4、判断用户请求的是否为 /about.html 关于页面if(url / || url /index.html){content h1首页/h1}else if(url /about.html){content h1关于页面/h1}//5、设置 Content-Type 响应头防止中文乱码res.setHeader(Content-Type, text/html; charsetutf-8)//6、使用 res.end() 把内容响应给客户端res.end(content)
})server.listen(80,function (){console.log(Server running at http://127.0.0.1)
})运行效果如下 补充${} 模板字符串语法
${} 是 JavaScript 中的模板字符串语法。在字符串中使用 ${} 可以插入变量或表达式的值。在这种情况下${url} 表示将变量 url 的值插入到字符串中。这种语法使得字符串拼接更加清晰和简洁。
模块化 模块化的基本概念
模块化是指解决一个复杂问题时自顶向下逐层把系统划分为若干模块的过程。对于整个系统来说模块是可组合、分解和更换的单元。 模块化规范 Node.js 中模块的分类 加载模块 注意在使用 require 加载用户自定义模块期间可以省略 .js 的后缀名。
Node.js 中的模块作用域 模块作用域的好处就是防止了全局变量污染的问题。
向外共享模块作用域中的成员
module 对象 module.exports 对象 接下来我们用代码来解释一下。
先创建两个自定义模块一个是自定义模块.js 另一个是 test.js然后我们 自定义模块.js 文件先不写任何内容在 test.js 中先去 require 自定义模块.js 中的内容试一下 运行效果如下 可以看见打印不出任何内容因为我们在导入另一个模块的时候我们导入的其实是另一个模块 module 的 exports 属性默认情况下 exports 属性就是空的这可以从上一小节讲的 module 对象 中的图里看到。
因此我们其实可以在 自定义模块.js 中对外共享一些本模块中的成员 此时我们在运行 test.js 查看现在是否 modules.export 为空了 可以看见不为空了有内容的。
共享成员时的注意点 exports 对象 代码验证如下
console.log(exports)
console.log(module.exports)
console.log(exports module.exports)运行效果如下 exports 和 module.exports 的使用误区 Node.js 中的模块化规范 npm 与包
什么是包 包的来源 为什么需要包 从哪里下载包 如何下载包 查看自己电脑上的 npm 版本 npm 初体验 这种传统方法就不演示了可以看出来很繁琐因此我们直接使用第三方包来完成一样的事情 在项目中安装包的命令 接下来我们来演示如何用 npm 下载 第三方包这里我直接使用 WebStorm 的终端进行下载了 可以看见此时就已经下载安装好了。
写代码来实现我们的时间格式化操作
//1、导入需要的包
const moment require(moment)//2、查阅官方文档明白第三方包要如何使用
const dt moment().format(YYYY-MM-DD HH:mm:ss)
console.log(dt)运行效果如下 初次安装后都多了哪些文件 可以检查一下自己的项目 注意程序员不要手动修改 node_modules 或者 package-lock.json 文件中的任何代码npm 包管理工具会自动维护它们。
安装指定版本的包 注意如果我们要切换第三方包的版本并不需要先卸载我们现有版本的包而是直接下新的即可新的会覆盖原来旧版本的包嗷。
包的语义化版本规范 包管理配置文件 多人协作的问题 如何记录项目中安装了哪些包 快速创建 package.json dependencies 节点 一次性安装所有的包 卸载包 devDependencies 节点 怎么知道哪些第三方包需要被保存到 devDependencies 哪些需要被保存到 dependencies 呢
这些其实在官方文档都会有说的查阅官方文档就行。
为什么下包速度慢 下包速度慢解决淘宝 NPM 镜像服务器 切换 NPM 的下包镜像源 nrm 小工具 包的分类
使用 npm 包管理工具下载的包共分为两大类分别是项目包和全局包。 好用的第三方包i5ting_toc 规范的包结构 package.json 为啥必须要包含 main 包入口的这个属性呢
这是因为在我们项目中使用 require 导入第三方包的时候其实走的就是这个 main 属性通过这个 main 属性我们才能正常使用这个包的功能即它是包的入口。
开发属于自己的包
假设我们现在需要开发的包叫 itheima-tools 包其需要实现下面的功能 那么接下来我们就按照下面的步骤开发我们自己的包 实现效果如下 然后初始化 package.json 如果你使用 WebStorm 进行文件创建的话可以发现其是自动生成的只要点击创建就可以了。
不难发现这个 package.json 包其实就是一个 json 配置对象 但是我们需要改一下改成 PPT 中的那样否则没办法发布到 NPM 的服务器上 上面需要解释的几个含义 main就是入口文件的位置 keywords这是被发布到 npm 服务器上时别人可以检索到这个包所使用的关键字有哪些 license所遵循的开源许可协议npm 官方推荐使用 ISC因此我们用这个即可 然后编写我们的包源码 将不同的功能进行模块化拆分 src 是我们的新创建的源码文件夹拆分的部分将全部放进该文件夹中。
编写包的说明文档 发布包
主要有以下几个步骤 注意在运行 npm login 命令之前必须先把下包的服务器地址切换为 npm 的官方服务器。否则会导致发布包失败 删除已发布的包 模块的加载机制 Express.js 初识 Express.js
Express.js 简介 进一步理解 Express Express 能做什么 Express 安装 这里看的课的老师用的 4.17.1 的版本我看了一下现在官网的最新版本是 4.19.2
按照包的语义化版本规范因为是只上升了第二位数的大小说明相较于 4.17.1 的版本现在最新的版本也只不过是新增了一些功能并且修复了一点 bug 而已因此我们直接安装使用最新版即可 查看版本 Express 创建 web 服务器 来实现一下
// 1、导入 Express
const express require(express)
// 2、创建 web 服务器
const app express()
// 3、启动 web 服务器
// 调用 app.listen(端口号启动成功后的回调函数)启动服务器
app.listen(80, (){console.log(express server running at http://127.0.0.1)
})运行效果如下 Express 监听 Get 和 Post 请求 示例代码如下
// 1、导入 Express
const express require(express)
// 2、创建 web 服务器
const app express()//4、监听客户端的 Get 和 Post 请求并向客户端响应具体的内容
app.get(/user,(req,res) {//调用 express 提供的 res.send() 方法向客户端响应一个 JSON 对象res.send({name: zs,age : 20,gender: 男})
})app.post(/user,(req,res) {//调用 express 提供的 res.send() 方法向客户端响应一个文本字符串res.send(请求成功)
})// 3、启动 web 服务器
app.listen(80, (){console.log(express server running at http://127.0.0.1)
})效果如下 获取 URL 中携带的查询参数 示例代码如下
app.get(/, (req,res){//通过 req.query 可以获取到客户端发送过来的 查询参数//注意默认情况下req.query 是一个空对象console.log(req.query)res.send(req.query)
})运行结果如下 此时我们加上查询参数运行结果将变为 获取 URL 中的动态参数 示例代码如下
//注意这里的 :id 是一个动态的参数
app.get(/user/:id,(req,res){// req.params 是动态匹配到的 URL 参数默认是空对象console.log(req.params)res.send(req.params)
})运行效果如下 我们不止可以写一个可以写多个动态参数
//注意这里的 :id 是一个动态的参数
app.get(/user/:id/:name,(req,res){// req.params 是动态匹配到的 URL 参数默认是空对象console.log(req.params)res.send(req.params)
})运行效果如下 托管静态资源
express.static() 简单测试一下 运行效果如下 托管多个静态资源目录 挂载路径前缀 调试工具nodemon 的安装与使用 Express 路由
什么是路由
广义上讲路由就是映射关系。
比如 在上图中路由就是按键与服务之间的映射关系。
Express 中的路由 实际项目中的示例程序 路由的匹配过程 路由的使用 这种方式之前就用过很多次了只要知道有这种用法即可实际的项目中我们不会采用这么直接的方式因此不再赘述。
模块化路由 创建路由模块 我们新创建一个 router.js 模块也就是一个自定义模块在其内部创建和挂载我们的路由模块
// 这是路由模块//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 a new user)
})
//4、向外导出路由对象
module.exports router注册路由模块
// 1、导入 Express
const express require(express)
// 2、创建 web 服务器
const app express()// 1、导入路由模块
const router require(./router.js)
// 2、注册路由模块
app.use(router)// 3、启动 web 服务器
app.listen(80, (){console.log(express server running at http://127.0.0.1)
})运行效果如下 可以发现路由模块化后也依然可以正常工作。
app.use() 函数的作用
一句话该函数的作用就是用来注册全局中间件的后面就会讲到了。
为路由模块添加前缀 Express 中间件
什么是中间件
中间件Middleware特指业务流程的中间处理环节。
比如 Express 中间件的调用流程 Express 中间件的格式 next 函数的作用 Express 中间件的初体验 代码示例如下
const express require(express)const app express()// 定义一个最简单的中间件函数
const mw function (req, res, next){console.log(这是最简单的中间件函数)//把流转关系转交给下一个中间件或者路由//有中间件转交给中间件没中间件就转交给路由next()
}app.listen(80, () {console.log(http://localhost)
})全局生效的中间件 示例代码如下
const express require(express)const app express()// 定义一个最简单的中间件函数
const mw function (req, res, next){console.log(这是最简单的中间件函数)//把流转关系转交给下一个中间件或者路由//有中间件转交给中间件没中间件就转交给路由next()
}//将 mw 注册为全局生效的中间件
app.use(mw)app.get(/,(req,res){console.log(Here is Home Page)res.send(Home page)
})app.get(/user,(req,res){res.send(User page)
})app.listen(80, () {console.log(http://localhost)
})运行效果如下 可以看见访问浏览器时是成功打印了 因为目前我们只定义了一个中间件因此在 mw 中间件函数执行结束之后因为没有其他中间件了于是 next() 函数将流转关系转交给了路由模块所以先打印 “这是最简单的中间件函数” 再打印 “Here is Home Page”。
定义全局中间件的简化形式 中间件的作用 示例代码
const express require(express)const app express()// 定义一个最简单的中间件函数
const mw function (req, res, next){//获取请求到达服务器的时间const time Date.now()//为 req 对象挂载自定义属性从而把时间共享给后面的所有路由req.startTime time//把流转关系转交给下一个中间件或者路由//有中间件转交给中间件没中间件就转交给路由next()
}//将 mw 注册为全局生效的中间件
app.use(mw)app.get(/,(req,res){res.send(Home pagereq.startTime)
})app.get(/user,(req,res){res.send(User pagereq.startTime)
})app.listen(80, () {console.log(http://localhost)
})运行效果 定义多个全局中间件 局部生效的中间件 定义多个局部中间件 注意调用顺序是从前往后的即先执行 mw1 再执行 mw2。
了解中间件使用的5个使用注意事项 中间件的分类 应用级别的中间件 路由级别的中间件 错误级别的中间件 注意错误级别的中间件必须注册在所有路由之后
Express 内置的中间件 express.json() 内置中间件
代码示例
const express require(express)
const app express()//注意除了错误级别的中间件其他的中间件必须在路由之前进行配置
//通过 express.json() 这个中间件解析表单中的 JSON 格式的数据
app.use(express.json())app.post(/user,(req,res){// 在服务器中可以使用 req.body 这个属性来接收客户端发送过来的请求体数据// 默认情况下如果不配置解析表单数据的中间件也就是 express.json()则 req.body 默认为 undefinedconsole.log(req.body)res.send(ok)
})app.listen(80, (){console.log(http://localhost)
})运行效果我们使用 postman 工具来进行测试
发送 JSON 类型的请求体数据如下 此时控制台中的输出如下 可以看见请求体数据被完美解析。
express.urlencoded() 内置中间件
示例代码如下
const express require(express)
const app express()//注意除了错误级别的中间件其他的中间件必须在路由之前进行配置
//通过 express.urlencoded() 这个中间件解析表单中的 JSON 格式的数据
//在这个函数内部我们还要传递一个固定的配置对象 extended 将其设置为 false
//这是固定的写法只需要记住不需要问为什么
app.use(express.urlencoded({ extended: false }))app.post(/book,(req,res){// 在服务器中可以使用 req.body 这个属性来接收客户端发送过来的 url-encoded 格式的数据// 默认情况下如果不配置解析 url-encoded 表单数据的中间件则 req.body 默认为空console.log(req.body)res.send(ok)
})app.listen(80, (){console.log(http://localhost)
})发送数据类型为 运行效果为 可以看见正常解析了数据。
第三方中间件 自定义中间件 实现如下 使用 Express 写 API 接口
1、创建基本的服务器
// app.js 主模块
// 导入 express
const express require(express)// 创建服务器实例
const app express()// 调用 app.listen() 方法指定端口号并启动 web 服务器
app.listen(80,(){console.log(Express server is running at http://localhost)
})2、创建 API 路由模块
// apiRouter.js 路由模块
const express require(express)const router express.Router()//在这里挂载对于的路由module.exports router然后在 app.js 中导入并注册路由模块
// app.js 主模块
// 导入 express
const express require(express)// 创建服务器实例
const app express()//导入路由模块
const router require(./apiRouter)
//把路由模块注册到 app 上
app.use(/api, router)// 调用 app.listen() 方法指定端口号并启动 web 服务器
app.listen(80,(){console.log(Express server is running at http://localhost)
})3、编写 Get 接口
// apiRouter.js 路由模块
const express require(express)const router express.Router()//在这里挂载对应的路由
router.get(/get, (req,res){//通过 req.query 获取客户端通过查询字符串发送到服务器的数据const query req.query//调用 res.send() 方法向客户端响应处理的结果res.send({stats: 0,//0 表示处理成功1 表示处理失败msg: Get 请求成功, // 状态描述data: query //需要响应给客户端的数据})
})module.exports router运行结果如下 4、编写 Post 接口
// apiRouter.js 路由模块
const express require(express)const router express.Router()//在这里挂载对应的路由
router.get(/get, (req,res){//通过 req.query 获取客户端通过查询字符串发送到服务器的数据const query req.query//调用 res.send() 方法向客户端响应处理的结果res.send({stats: 0,//0 表示处理成功1 表示处理失败msg: Get 请求成功, // 状态描述data: query //需要响应给客户端的数据})
})router.post(/post, (req,res){//通过 req.body 获取客户端发送到服务器的请求体数据const body req.body//调用 res.send() 方法向客户端响应处理的结果res.send({stats: 0,//0 表示处理成功1 表示处理失败msg: Post 请求成功, // 状态描述data: body //需要响应给客户端的数据})
})module.exports router要解析表单数据别忘了在导入路由之前先添加配置解析表单数据的中间件
// app.js 主模块
// 导入 express
const express require(express)// 创建服务器实例
const app express()//配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false}))
app.use(express.json())//导入路由模块
const router require(./apiRouter)
//把路由模块注册到 app 上
app.use(/api, router)// 调用 app.listen() 方法指定端口号并启动 web 服务器
app.listen(80,(){console.log(Express server is running at http://localhost)
})运行效果如下 接口的跨域问题 接口跨域问题是指在Web开发中由于浏览器的同源策略Same-Origin Policy导致在一个域下的网页无法直接访问另一个域下的资源。跨域指的是在浏览器中当一个页面的脚本请求访问另一个域下的资源时如果这个资源的域名、协议或端口与当前页面所在的域不一致就会引发跨域问题。
跨域问题会影响到包括Ajax请求、Web字体加载、嵌入式框架如iframe加载等场景。具体来说如果你在一个网页中使用Ajax请求另一个域下的数据浏览器会阻止这个请求因为涉及到跨域。
解决接口跨域问题的方法有很多包括使用代理服务器、JSONP、CORS跨域资源共享等。CORS是一种比较常用的解决方案它通过在服务器端设置一些响应头来告诉浏览器允许跨域请求。JSONP则是一种利用
实际开发中我们推荐使用 CORS 的方法来解决跨域问题。
使用 CORS 中间件解决跨域问题 第一步安装 第二步和第三步在路由之前先配置并注册 cors 中间件到 app.js 上
// app.js 主模块
// 导入 express
const express require(express)// 创建服务器实例
const app express()//配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false}))
app.use(express.json())//在路由之前先配置 cors 中间件解决跨域问题
const cors require(cors)
//注册 cors 中间件
app.use(cors())//导入路由模块
const router require(./apiRouter)
//把路由模块注册到 app 上
app.use(/api, router)// 调用 app.listen() 方法指定端口号并启动 web 服务器
app.listen(80,(){console.log(Express server is running at http://localhost)
})这样就可以解决跨域问题啦。
什么是 CORS CORS 的注意事项 CORS 响应头部 -Access-Control-Allow-Origin CORS 响应头部 -Access-Control-Allow-Headers CORS 响应头部 -Access-Control-Allow-Methods CORS 请求的分类 简单请求 预检请求 在浏览器与服务器正式通信之前浏览器会先发送 OPTION 请求进行预检以获知服务器是否允许该实际请求所以这一次的 OPTION 请求称为 ”预检请求“ 。服务器成功响应预检请求后才会发送真正的请求并且携带真实数据。
简单请求和预检请求之间的区别 数据库与身份认证 注意这一章节的学习中省略了 MySQL 相关的基础内容如果不会的话建议先去系统学一下 MySQL 捏。
这里只讲 Express 中如何操作 MySQL 数据库嗷。
测试的表数据如下 在 Express 中操作 MySQL
在项目中操作 MySQL 数据库的步骤 安装 mysql 模块 配置 mysql 模块 示例代码如下
//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql require(mysql)//2、建议与 mysql 数据库的连接关系
const db mysql.createPool({host: 127.0.0.1, //数据库的 ip 地址user: root, //登录数据库的账号password: 123456, //登录数据库的密码database: node //指定要操作哪一个数据库
})测试一下 mysql 模块是否能正常工作
//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql require(mysql)//2、建议与 mysql 数据库的连接关系
const db mysql.createPool({host: 127.0.0.1, //数据库的 ip 地址user: root, //登录数据库的账号password: 123456, //登录数据库的密码database: node //指定要操作哪一个数据库
})// 测试 mysql 模块能否正常工作
// select 1 这条语句没有任何意义只是用来检查 mysql 能否正常工作
db.query(select 1,(err, results){// mysql 模块工作期间报错了if(err){return console.log(err.message)}//否则就是能够正常的执行 SQL 语句console.log(results)
})测试运行结果如下 可以看见我们的 mysql 模块是没有问题的。
使用 mysql 模块操作 MySQL 数据库
查询数据 示例代码如下
//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql require(mysql)//2、建议与 mysql 数据库的连接关系
const db mysql.createPool({host: 127.0.0.1, //数据库的 ip 地址user: root, //登录数据库的账号password: 123456, //登录数据库的密码database: node //指定要操作哪一个数据库
})// 查询 users 表中所有的数据
const str select * from user
db.query(str,(err, results){// mysql 模块工作期间报错了if(err){return console.log(err.message)}//否则就是能够正常的执行 SQL 语句console.log(results)
})运行结果如下 注意如果执行的是 select 查询语句则执行的结果是数组。
插入数据 示例代码
//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql require(mysql)//2、建议与 mysql 数据库的连接关系
const db mysql.createPool({host: 127.0.0.1, //数据库的 ip 地址user: root, //登录数据库的账号password: 123456, //登录数据库的密码database: node //指定要操作哪一个数据库
})// 向 user 表中新增一条数据其中username的值为 Spiderpassword 的值为123
const user {username:Spider, password:123}
//定义待执行的 SQL 语句
const sqlStr insert into user (username, password) values (?, ?)
//执行 SQL 语句
db.query(sqlStr,[user.username,user.password],(err,results){if(err) return console.log(err.message)// 注意如果执行的是 insert into 插入语句则 results 是一个对象// 可以通过 affectedRows 属性来判断是否插入数据成功if(results.affectedRows 1) console.log(插入数据成功)
})插入数据的便捷方式 示例代码
//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql require(mysql)//2、建议与 mysql 数据库的连接关系
const db mysql.createPool({host: 127.0.0.1, //数据库的 ip 地址user: root, //登录数据库的账号password: 123456, //登录数据库的密码database: node //指定要操作哪一个数据库
})// 向 user 表中新增一条数据其中username的值为 Spiderpassword 的值为123
const user {username:Spider, password:123}
//定义待执行的 SQL 语句
//insert into 表名 set ?
const sqlStr insert into user set ?
//执行 SQL 语句
// 参数也不需要用数组形式了直接将原对象进行插入即可类似于一个 JavaBean
db.query(sqlStr,user,(err,results){if(err) return console.log(err.message)// 注意如果执行的是 insert into 插入语句则 results 是一个对象// 可以通过 affectedRows 属性来判断是否插入数据成功if(results.affectedRows 1) console.log(插入数据成功)
})
运行结果如下 数据库中也是正常的新增了数据 更新数据 示例代码
//mysql-cfg.js 数据库模块
//1、导入 mysql 模块
const mysql require(mysql)//2、建议与 mysql 数据库的连接关系
const db mysql.createPool({host: 127.0.0.1, //数据库的 ip 地址user: root, //登录数据库的账号password: 123456, //登录数据库的密码database: node //指定要操作哪一个数据库
})// 向 user 表中修改一条数据
const user { id: 3, username:阿斯顿, password:123 }
//定义待执行的 SQL 语句
const sqlStr update user set username?,password? where id?
//执行 SQL 语句
db.query(sqlStr,[user.username,user.password,user.id],(err,results){if(err) return console.log(err.message)// 注意如果执行的是 update 更新语句则 results 是一个对象// 可以通过 affectedRows 属性来判断是否更新数据成功if(results.affectedRows 1) console.log(更新数据成功)
})
运行结果如下 更新数据的便捷方式 删除数据 标记删除 前后端中的身份认证
Web 开发模式
目前主流的 Web 开发模式有两种分别是
1、基于服务端渲染的传统 Web 开发模式
2、基于前后端分离的新型 Web 开发模式
基于服务端渲染的传统 Web 开发模式 基于前后端分离的新型 Web 开发模式 如何选择 Web 开发模式 身份认证
什么是身份认证
为什么需要身份认证 不同开发模式下的身份认证 HTTP 协议的无状态性 如何突破 HTTP 无状态的限制 什么是 Cookie Cookie 在身份认证中的作用 Cookie 不具有安全性 注意千万不要使用 Cookie 存储重要且隐私的数据比如用户的身份信息、密码等。
提高身份认证的安全性 Session 的工作原理 在 Express 中使用 Session 认证
配置 Session
只需要下面几步就可以使用 Session 认证了嗷 配置对象中的 secret 属性是一串字符串用来加密用的。
接下来我们完成一下这些事情
安装 express-session 中间件 开始配置 express-session 的全局中间件
// app.js 主模块
// 导入 express
const express require(express)// 创建服务器实例
const app express()// 引入session
const session require(express-session)
// 注册 session
app.use(session({secret: hahaha,resave: false,saveUninitialized: true
}))//配置解析表单数据的中间件
app.use(express.urlencoded({ extended: false}))
app.use(express.json())//在路由之前先配置 cors 中间件解决跨域问题
const cors require(cors)
//注册 cors 中间件
app.use(cors())//导入路由模块
const router require(./apiRouter)
//把路由模块注册到 app 上
app.use(/api, router)// 调用 app.listen() 方法指定端口号并启动 web 服务器
app.listen(80,(){console.log(Express server is running at http://localhost)
})向 Session 中存数据 从 Session 中取数据 清空 Session 注意只是清空了当前客户端的 Session 这并不会影响到其他客户端的 Session。
因为之前说过 Session 的工作原理每个 Session 都会对应一个客户端浏览器所自动存收的一个 Cookie因此相当于各个客户端之间是隔离连接的互不影响至于底层是怎么实现的应该是在这个 express-session 第三方包中自动实现的我们只要懂得怎么使用即可。
了解 Session 认证的局限性 什么是 JWT
JWT英文全称JSON Web Token是目前最流行的跨域认证解决方案。
JWT 的工作原理 JWT 的组成部分 JWT 的三个部分各自代表的含义 JWT 的使用方式 注意千万别忘记了在 token 字符串前加 Bearer 这个字符串然后后面还要跟一个空格才能再跟 token 字符串
比如我们在 postman 中要带 token 的话那么形式应该是下面这样 在 Express 中使用 JWT
主要有下面几个步骤 上图中的第三个参数配置对象里我们配置了该 Token 的过期时间为 30s如果要设置成分钟则后缀用 m 小时的话设置为 h 即可。 注意只要配置成功了 express-jwt 这个中间件就可以把解析出来的用户信息挂载到 req.user 属性上。
换句话说就是req 本身是没有 user 属性的但是只要配置成功了 express-jwt 这个中间件后req 就有一个 user 属性了该属性是由该中间件创建的。
而这个 user 对象中包含多少信息是由我们自己决定的也就是在登录成功之后我们进行加密的用户信息对象信息有多少那么 user 对象中就有多少信息。
比如我们上面的示例中将 username 进行了加密那么被创建的 user 对象就会只有一个 username 属性。
如果我们的访问请求携带了 token 进行 API 访问的话其返回值会有下面两个额外的属性 iat 和 exp 不过不用管这是这个 JWT 第三方工具包用来控制过期时间用的两个属性。
捕获解析 JWT 失败后产生的错误