本文主要是介绍Node.js从入门到入土,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Node.js从入门到入土
- Node.js系统模块
- fs模块
- 读取文件(readFile)
- 写入文件(writeFile)
- path模块
- 路径拼接 (path.join)
- 获取路径中的文件名字(path.basename)
- http模块
- 创建基本的web服务器
- request对象
- response响应对象
- node.js中的模块化
- node模块化原理
- module对象
- exports
- modules.exports和exports的区别
- node遵循的模块化规范
- npm与包
- 初识express
- 使用express创建web服务器
- 使用express创建静态资源服务器
- express路由
- express路由模块的基本使用
- 路由模块添加统一前缀
- express中间件
- 中间件的作用
- next参数的作用
- 全局生效的中间件
- 局部生效的中间件
- 使用中间件的注意事项
- 中间件的分类
- 自定义中间件
- 在中间件监听数据行为
Node.js系统模块
fs模块
使用fs模块(导入)
const fs = require("fs");
读取文件(readFile)
目录结构如下
基本使用方法如下
fs.readFile('路径','可选参数',(err,data) => { 回调函数,错误有限原则 })
//index.jsconst fs = require("fs");fs.readFile("./1.text", "utf-8", (err, data) => {console.log(data);});
// 1.texthello world!
运行结果
写入文件(writeFile)
基本使用方法如下
fs.writeFile('路径','写入内容','可选参数',(err,data) => { 回调函数,错误有限原则 })
// index.jsconst fs = require("fs");fs.writeFile("./2.text", "hello world鸭", [], () => {console.log(111);});
运行结果
写入成功
writeFile的结果是覆盖性的,也就是第二次的执行结果不会添加到第一次的后面而是直接替换整个文件
path模块
某些变量是可以在node中直接使用而无须导入的,__dirname,当前执行文件目录的绝对路径
console.log(__dirname)
执行结果
node的系统path模块提供了一些更高级的操作路径的方法
const path = require('path')
路径拼接 (path.join)
基本使用
path.join(...[paths])
const path = require("path");console.log(path.join(__dirname, "1.text"));
获取路径中的文件名字(path.basename)
const path = require("path");const urlName = path.join(__dirname, "1.text");console.log(path.basename(urlName));
运行结果
http模块
node.js用于创建web服务器的模块
服务器和普通电脑的区别在于,服务器安装了web服务器软件,IIS,Apache等,通过安装这些服务器软件,就可以将一台普通电脑变成一台web服务器。
导入http模块
创建基本的web服务器
1、引入http模块
const http = require('http')
2、创建web服务实例
const server = http.createServer()
3、监听客户端的请求动作
server.on("request", (req, res) => {// req是请求对象 res是返回对象console.log(req, res);});
4、监听端口启动服务器
server.listen("3001", () => {console.log("嘿嘿嘿 我的服务在http://localhost:3001端口上启动成功啦!");});
执行index.js文件
此时在浏览器打开localhost:3001会将请求信息打印到终端上
request对象
server服务器监听浏览器的请求动作的第一个参数req具有以下的key
url:从哪儿发来的请求
method:请求的方法
response响应对象
server服务器监听浏览器的请求动作的第二个参数res具有以下的key
setHeader:一个方法,用于设置响应头
end:一个方法,用于向浏览器端返回数据
node.js中的模块化
以模块的来源进行分类,可以将Node.js中的模块分为以下三大类 系统模块如(fs,path,http),自定义模块用户自定义的,第三方模块用户引入的
引入方法都是使用require
const 模块名 = require('xx路径')
node模块化原理
思考如下问题
为什么在每个node.js模块中,我们都可以自由的使用require、module这些没有定义过的变量用于模块导入导出呢?
《深入浅出node.js》如是说
实际上,每一个node模块都是被一个函数包裹起来的闭包(正是因此在node.js文件中模块才不会污染到全局变量)
(function(exports, require, module, __filename, __dirname) {// 模块内容});
module对象
从模块化原理一章中可以得知无需引入可以直接使用module对象。那么module对象里面到底有什么呢?百闻不如一见直接打印
console.log(module)
从这张图中我们也知道了为什么可以直接使用 module.export
exports
在node模块中,我们可以使用module.exports将模块里的变量或函数暴露给其他模块进行使用。其他模块使用require引入之后就可以使用。(模块默认导出为空对象{},模块导出永远以module.exports的导出对象为准)如
module.exports = { name:'wxs'}
!!!!
需要注意的是,如果我们需要实现上例
以下三种写法都是正确的
module.exports = { name:'wxs'}module.exports.name = 'wxs'exports.name = 'wxs'
但是如果写成这样就会导出失败
exports = { name:'wxs' }
接下来开启下一章的内容
modules.exports和exports的区别
首先给出答案,没有区别,在node文件中打印
module.exports === exports
直接说明 exports和module.exports指向的是同一个对象,但是node只以module.exports的导出对象为准。如果写成exports = 新对象的形式就改变了exports的指向,改变之后的exports就不指向module.exports了,从而无法导出。
node遵循的模块化规范
commonJS是node遵循的模块化规范。不要把这个想的有多复杂,我们在刚刚已经把它用的差不多了,在这一小节中总结一下。
CommonJS规定
- 每个模块内部,module对象代表当前模块
- module对象的exports属性代表对外的接口
- 模块中使用require来导入外部模块
npm与包
在node.js中,在js文件中使用的第三方模块又称作包。不同于内置模块与用户自定义模块,包是网络上的第三方个人或者第三方团队开发
在项目中使用第三方包的命令
npm i 包名称
安装之后项目目录文件夹会多出两个文件
node_modules和package
其中node_modules文件夹包含了所下载的全部第三方包,package-lock记录了包名称、版本号等信息。
执行
npm uninstall xxx包名称
之后会自动将包依赖从package-lock中移除
初识express
express之于node,有点类似于jquery之于js原生代码。比如我们要新建一个web服务器,原生node写法如下
使用express创建web服务器
安装
npm i express
const express = require("express");const app = express();app.get("/", (req, res) => {res.send({name: "wxs",});});app.listen(3000, () => {console.log("your localServer is running on http://localhost:3000");});
且相比较之下,express还有很多优势,如中间件,创建静态资源服务器等…
使用express创建静态资源服务器
express提供了一个很好用的方法用于创建一个静态资源服务器。express.static(),例如,通过
express.static('public')
就可以将public目录下的css、图片、icon等静态资源暴露出去。
express在指定的目录中查找静态资源,因此,目录名不会出现在URL中,举个小🌰
编辑index.js,在 const app = express() 后新加一行
app.use(express.static("public"));
第二步,在文件同级目录下新建public文件夹中新建images文件夹,再随便找张图片放进去
第三步
如果有多个静态资源文件夹,只需多次调用即可,另外,如果想在取静态资源时加上路径前缀,可以写成 app.use('/xxx(路径)',express.static('xxx(路径)'))
的形式
express路由
在express中,路由指的是客户端的请求和服务端请求函数之间的关系,基本调用关系如下
app.METHOD('URL',处理函数)app.get('url',(req,res) => {处理函数})
express路由模块的基本使用
为了方便对express进行更好的管理,express不建议将路由直接挂载到app上,而是推荐将路由抽离成单独的组件。
实际上使用路由模块就两步,第一步编写路由模块导出,第二步引入并使用
- 文件目录中新建routes作为存放路由模块的文件夹,创建一个路由模块(routerTest.js)编辑如下
const express = require("express");const route = express.Router();route.get("/", (req, res) => {res.end("您现在看到的是首页");});module.exports = route;
- 主文件引入并使用
const routeTest = require("./routes/routerTest");const express = require("express");const app = express();app.use(routeTest);app.listen(3000, () => {console.log("your localServer is running on http://localhost:3000");});
直接运行,postman结果如下
路由模块添加统一前缀
路由模块添加统一前缀的方法和添加静态资源服务器时一致,直接改写app.use加上第一个参数
app.use('/XXX',routeTest)
express中间件
express中间件本质上就是一个function处理函数,与路由处理函数不同的是,中间件处理函数必须包含next参数,而路由处理函数只需要包含req和res,客户端发送请求后,服务端会根据中间件定义的顺序依次调用中间件。
中间件的作用
express中的中间件是共享一套req和res的,因此我们可以在上游中间件中为res,req提供属性和方法供下游中间件使用,tips:中间件一定要调用next方法,否则无法过渡到下游中间件
next参数的作用
next参数是一个函数,它是中间件跳转的关键,表示将操作转交给下一个操作或者路由。百闻不如实际操作
直接定义一个中间件
const middleWare = (req,res,next) => {console.log('我是一个中间件')// 必须调用!!!不然无法跳转至下一个中间件会造成流程阻断next()
}
全局生效的中间件
上一节中我们已经定义了一个最简单的中间件函数,这一章将要使用它并使它全局生效。编辑index.js文件如下
const express = require("express");const app = express();const middleWare = (req, res, next) => {console.log("我是一个中间件");// 必须调用!!!不然无法跳转至下一个中间件会造成流程阻断next();};app.use(middleWare);app.get("/", (req, res) => {res.send("hello world");});app.listen(3000, () => {console.log("your localServer is running on http://localhost:3000");});
代码表明这在处理get请求之前先经过middleware中间件,控制台会打印文字,看实际效果
局部生效的中间件
全局中间件是在服务端处理任何请求时都会执行的中间件,而局部中间件只有在服务端处理某特定请求时才会执行。
基本使用
app.get('xxx(请求地址)',middleWare,(req,res) => {})
使用中间件的注意事项
-
定义中间件必须要在定义路由之前
由于中间件执行顺序是从上至下的,所以定义中间件需要在定义路由之前,否则中间件无法正常使用。 -
客户端发过来的请求可以连续调用多个中间件
-
执行完中间件的逻辑代码一定要调用next函数
-
多个中间件之间是共享req和res对象的,因此下游中间件可以接收到上游中间件处理之后的req和res
中间件的分类
- 应有级别的中间件
使用app.use,app.get,这种挂载到app实例上的中间件叫做应用中间件,其中app.use是全局中间件,挂载到具体方法上的比如app.get是局部中间件。 - 路由级别的中间件
顾名思义,挂载到路由上的中间件,在使用方法上,路由中间件和应用中间件保持一致。以上例我们创建的路由模块为例。
const express = require("express");const route = express.Router();route.get("/", (req, res) => {res.end("您现在看到的是首页");});module.exports = route;
- 错误级别的中间件
用来捕获程序中的异常,防止程序因出错而崩溃,错误处理中间件必须包含四个形参,从左到右分别是err,req,res,next,报错需要主动暴露,然后在错误处理中间件中进行处理,基本使用如下
app.get("/", (req, res) => {throw new Error("服务器发生了错误");res.send("hello world");});app.use((err, req, res, next) => {res.send("很抱歉服务器发生了错误");});
错误级别中间件必须注册在所有路由之后!
- 内置中间件
express内置了三个常用的中间件,极大的提高了开发效率
第一个其实上文中已经提到过,创建静态资源服务器的中间件
express.static
app.use(express.static('xxx(路径名)'))
express.json
用于解析JSON格式的请求体的数据
// 配置处理json格式请求体的中间件app.use(express.json())
express.urlencoded
用于解析URL-encoded格式的请求体数据
// 配置处理URL-encoded格式请求体的中间件app.use(express.urlencoded())
- 第三方中间件
由第三方组织或个人开发的中间件,按需引入并使用
具体使用及配置参数需要参考第三方中间件官方文档
// 下载npm i xxxconst XXX = require('xxx');app.user(XXX)
自定义中间件
自定义中间件很重要,值得新开一小节,上文中已经说到,中间件本质上是一个函数。所以自定义中间件似乎也没有辣么难啦。自定义行为因人而异,这里只简要介绍基本使用
const myMiddleWare = (req,res,next) => {console.log('这里是我自定义的逻辑');next()}app.use(myMiddleWare )
在中间件监听数据行为
我们如果需要在中间件中处理客户端发送过来的数据,需要使用req对象监听data事件。
req.on('data',() => { // 回调函数 })
如果客户端的数据接收完毕会触发end事件
req.on('end',() => { // 回调函数 })
最终我们开发完中间件之后往往会将它封装成函数。
这篇关于Node.js从入门到入土的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!