Node 学习笔记

166 阅读11分钟

初识Node

Node.js 是一个开源和跨平台的 JavaScript 运行时环境,它允许开发者使用 JavaScript 来编写服务器端的代码。Node.js 不是一种编程语言,也不是框架,它是一个使 JavaScript 能在浏览器之外运行的平台。有着基于V8引擎、事件驱动和非阻塞I/O、单线程、npm生态系统、跨平台、模块化、适用场景广的特点。

企业微信截图_17016916392525.png

Node与游览器的区别

Node.js 和浏览器都是JavaScript的运行环境,但它们在许多方面存在显著差异。这些差异主要体现在用途、API、运行环境等方面。

  1. 用途

    • Node.js 主要用于服务器端编程。它允许开发者使用JavaScript来编写服务器端的脚本,创建动态网页内容之前,这通常是由PHP、Python、Ruby等语言完成的。
    • 浏览器则是客户端JavaScript的执行环境,用于为用户提供交互式的网页应用。浏览器中的JavaScript通常处理用户界面、操作DOM、发送AJAX请求等任务。
  2. API

    • Node.js 提供了一系列适合服务端开发的API,例如文件系统操作、网络(HTTP、TCP、UDP、DNS、TLS/SSL等)、流数据处理、加密等。
    • 浏览器提供了一套不同的API,用于与用户界面交互,如操作DOM、监听用户事件、渲染图形和动画、执行Web存储等。
  3. 运行环境

    • Node.js 运行在V8 JavaScript引擎之上,这也是Chrome浏览器使用的JavaScript引擎,但它不依赖于浏览器,可以独立运行在各种操作系统上。
    • 浏览器是一个为展示网页而设计的软件,包含了JavaScript引擎(如Chrome的V8、Firefox的SpiderMonkey、Safari的JavaScriptCore等),并在这些引擎上运行JavaScript代码。
  4. 模块系统

    • Node.js 使用CommonJS模块系统,通过require函数来加载模块,并通过module.exportsexports来导出模块。
    • 浏览器最初没有内置模块系统,但现代浏览器已经开始支持ES6模块,通过importexport语句来实现模块功能。
  5. 异步处理

    • Node.js 采用非阻塞I/O模型,强调事件驱动和异步处理,这使得Node.js非常适合处理大量的并发连接和I/O密集型任务。
    • 浏览器的JavaScript执行也是事件驱动的,但它更专注于与用户的交互、动画等任务。
  6. 全局对象

    • Node.js 的全局对象是global
    • 浏览器的全局对象是window,还有document对象,用于操作网页的DOM结构。
  7. 安全性

    • Node.js 由于运行在服务器端,对文件系统有直接的访问权限,因此安全性问题需要特别关注。
    • 浏览器运行在沙箱环境中,限制了对本地文件系统的访问,以减少安全风险。
  8. 更新频率

    • Node.js 的版本更新比较频繁,社区也经常推出新的工具和库。
    • 浏览器的更新也很频繁,但是通常受限于用户的升级习惯,新特性的采用可能会有所延迟。

Node的入门模块

简单说一下几个入门的模块,也是我最近学习使用的模块。

  • fs模块: 文件操作模块,提供了文件的读写能力。
  • path模块: 路径模块,提供了路径操作的实用工具。
  • http模块: 提供了HTTP服务器功能和客户端功能。

文件操作模块

读取文件

fs.readFile(path,[options],callback)

参数:

  • path: 必选,文件的路径。
  • options: 可选,表示用什么编码格式读取文件
  • callback: 必选,读取完的回调
const fs = require('fs')

fs.readFile('./input.txt','utf8',(err,data) => {
    if(err) // 读取成功的时候,err为null
        console.log("读取文件失败!",err)
    console.log("读取成功:",data)
})

写入文件

fs.writeFile(file,data,options,callback)
参数:

  • file: 必选,文件的路径
  • data: 必选,写入的内容
  • options: 可选,写入的编码格式
  • callback 必选,写入的回调
fs.writeFile('./input.text','伊卡洛斯','utf8',(err) => {
    console.log(err) // 成功时,为null,写入的时候回覆盖原内容
})

路径模块

path.join([...paths]): 路径拼接
path.basename(path,ext): 获取路径中的文件名 ,ext为要去除的尾缀 path.extname(path): 获取路径中的文件扩展名

const path = require('path')

console.log(path.join('/a','../','/b')) // \b

console.log(path.basename('./a/b/c/index.html','x.html')) // inde

console.log(path.extname('./a/b/c/index.html')) // .html

http模块

创建最基本的web服务器

  1. 导入http模块 const http = require('http')
  2. 创建web服务器实例 http.createServe()
  3. 给实例绑定request事件,监听客户端请求 server.on('request',callback)
  4. 启动服务器 server.listen(端口号,callback)
// 导入http模块
const http = require('http')
// 创建web服务器实例
const server = http.createServer()
// 绑定request事件
server.on('request',(req,res) => {
    // req.url 是客户端请求的 URL 地址
  const url = req.url
  // req.method 是客户端请求的 method 类型
  const method = req.method
  const str = `Your request url is ${url}, and request method is ${method}`
  console.log(str)
  // 调用 res.end() 方法,向客户端响应一些内容

  // 设置响应头 Content-Type,解决中文乱码问题
  res.setHeader('Content-Type', 'text/html; charset=utf-8')
  if(url == '/')
    res.end(str+"哈哈")
  else 
    res.end('<h1>你打错了吗?</h1>')
})

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

Express

Express是基于Node.js平台,快速、开放、极简的Web开发框架,和Node内置的http模块相似,是专门用来创建Web服务器的。本质上也只不过是npm上的第三方包。

Express的基本使用

  • 导入Express
  • 创建基本的Web服务器
  • 监听Get请求
  • 监听Post请求
  • 将内容响应给客户端
  • 获取URL中的查询参数
  • 获取URL中的动态参数
// 1. 导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()

// 3. 监听客户端的 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('请求成功')
})
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)
})

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

托管静态资源

通过express.static(path),将图片、css、js文件等对外开放,path为文件夹名,会将该文件夹下的文件对外开放。

let app = express();

app.use('/files',express.static('./files')) // 将files文件夹下的文件暴露给访问者,访问者通过访问/files/文件名 可以访问到files文件夹下对应的文件。

app.use(express.static('./files')) // 将files文件夹下的文件暴露给访问者,访问者通过访问 /ip:端口/文件名 可以访问到files文件夹下对应的文件。

Express路由

路由简单来说就是映射关系,Express中的路由指的就是用什么回调函数来处理对应的请求。
app.METHOD(PATH,HANDLER) Express的路由分为3部分: 请求类型METHOD、请求的URL地址PATH、处理函数HANDLER;请求到达Express时,首先会通过路由,在匹配对应的处理函数。匹配顺序按照路由的生成顺序。

路由的基本使用

最简单的用法

const app = express()

// 简单创建get请求和post请求 path为'/' 的路由
app.get('/',callback); 
app.post('/',callback);

模块化路由

将路由抽离app,分离成单独的模块

  1. 创建单独的路由.js文件
  2. 调用express.Router() 创建路由实例
  3. 在路由实例上挂载具体的路由
  4. app.use() 使用路由模块
// 路由文件 router.js

// 引入express
const express = require('express');
// 创建路由实例
const router = express.Router();
// 挂载路由
router.get('/a',callBack);
router.post('/b',callBack);
// 导出路由模块
module.exports = router

// app.js

const express = require('express');
const app = express();
const Router = require('./router.js')

app.use(Router);

Express 中间件

中间件的概念

中间件(Middleware),指的是业务流程中的中间处理环节;当请求到达Express服务器后,调用对应的中间件,对该次请求进行处理。简单来说中间件就是一个处理函数,相当于把部分功能封装到一个地方。中间件函数的形参有3个(req,res,next),next是下一个需要调用中间件或者路由,是必须参数。

自定义中间件


// myMiddleWare 是我自定义的一个中间件函数
const myMiddleWare = function(req.res, next) {
    console.log('我的自定义函数')
    //注意:在当前中间件的业务处理完毕后,必须调用next()函数 
    //表示把流转关系转交给下一个中间件或路由
    // 多个中间件共享一份req、res
    next()
}

全局中间件

//定义中间件函数mw1
const mw1 = function(req,res,next) {
    console.log("这是中间件函数")
    next()
}
//定义中间件函数mw2
const mw2 = function(req,res,next) {
    console.log("这是中间件函数2")
    next()
}

app.use('/',mw1,mw2)

app.get('/user',(req, res) => {
    res.send('111')
})

局部中间件

//定义中间件函数mw1
const mw1 = function(req,res,next) {
    console.log("这是中间件函数")
    next()
}

// 使用局部中间件mw1,只在/user路由下生效
app.get('/user',mw1,(req, res) => {
    res.send('111')
})

中间件注意要点

  1. 在路由前注册中间件
  2. 客户端的请求可以用多个中间件处理
  3. 中间件中一定要有next()函数,且在next()函数后不要写其他内容 next是下一个中间件或者路由,列如 app.use('/',mw1,mw2) 中,mw1 的next就是mw2
  4. 多个中间件间共享req和res

中间件分类

常见的中间件有:应用级的中间件、路由级的中间件、错误级别的中间件、Express内置的中间件、第三方中间件。

应用级别的中间件

通过app.use/get/post 绑定到app实例上的中间件

路由级别的中间件

用法和应用级的没什么区别,只不过路由中间件是绑定到express.Router()实例上的中间件。

错误级别的中间件

其作用是专门用来捕获整个项目中发生的错误异常,避免项目崩溃的中间件,其有4个形参(err,req,res,next)

内置的中间件

express提供的内置的中间件,和JS内置的API差不多,常用的有3个

  • express.static 托管静态资源
  • express.json 解析JSON格式的请求体数据
  • express.urlencoded 解析URL-encoded格式的请求体数据

第三方中间件

通过npm install 安装,require导入,app.use 挂载的中间件

Express 解决跨域问题

调用接口的时候难免遇到跨域问题,我们现在常见的解决方案有2种
1.CORS解决跨域

CORS(Cross-Origin Resource Sharing,跨源资源共享)是一个系统,它由一系列传输的 HTTP 标头组成,这些 HTTP 标头决定浏览器是否阻止前端 JavaScript 代码获取跨源请求的响应。

同源安全策略默认阻止“跨源”获取资源。但是 CORS 给了 web 服务器这样的权限,即服务器可以选择,允许跨源请求访问到它们的资源。

1. npm install cors
2. const cors = require('cors')
3. app.use(cors())  // 挂载cors
4. app.on('request',(req,res) => {
    res.end('Hello Nodejs');
    res.setHeader('Access-Control-Allow-Origin','*') //设置res.setHeader 解决跨域问题,告诉浏览器,该请求允许跨域,不要阻拦。 
})

// 复制即可运行的例子
let express = require('express')
const cors = require('cors')
let app = express()

app.use(cors())
app.use(express.static('./public'))
app.get('/',(req,res) => res.end('hello world'))
app.use(express.urlencoded({extended:false}))
app.use(express.json())

app.post('/post',(req,res) => {
    const result = req.body
    res.end(result.name)
})

app.listen(3000,() => console.log('server is running...'))

app.on('request',(req,res) => {
    res.end('Hello Nodejs');
    res.setHeader('Access-Control-Allow-Origin','*')

    // req.url 是客户端请求的 URL 地址
    const url = req.url
    // req.method 是客户端请求的 method 类型
    const method = req.method

    console.log(method,url)
})

2.JSONP解决跨域(只支持GET请求,原理是利用srcript标签支持跨域访问)
JSONP解决跨域的过程很简单,举个例子大家就明白了。

第一步,客户端通过script标签的src向服务器端发起get请求,并告诉服务器回调的时候执行什么函数。

 function jsonpCallback(data) {  // 告诉服务器回调函数,里面的内容就相当于 .then(data => {...})
     console.log(data); // 处理数据 
  }  
 var script = document.createElement('script');   
 script.src = 'http://example.com/data?callback=jsonpCallback'; // 发起请求,并告诉服务器回调时回调的函数。
 document.body.appendChild(script); // 执行script,等服务器返回相关的js语句执行相应的回调内容。

第二步,服务器接受到请求,并执行相应的回调。

    jsonpCallback({name:'123'}) // 执行对应的回调函数,返回到客户端的时候,客户端执行这条语句,就可以通过jsonpCallback函数获取到对应的响应数据了。

总结

一口吃不成胖子,本来打算买书来学,但是node更新太快,书上的内容有点跟不上了。node的模块很多,这里只介绍了一点点,后面慢慢每天学一点点吧。日子总是要过的,还能离不成吗?