Node 基础

基础概念

1 什么是Node.js
Node.js是一个基于Chrome V8 引擎(V8引擎的运行效率更高)的JavaScript运行环境。
V8引擎负责解析和执行js代码,内置API提供了一些能力,让我们可以做后端的一些事情。
在这里插入图片描述
注意:

  • 浏览器是JavaScript的前端运行环境;
  • Node.js是JavaScript的后端运行环境;
  • Node.js中无法调用DOM和BOM等浏览器内置API。
    官网地址:
    https://nodejs.org/zh-cn/

2 Node.js可以做什么

  • 可以基于Express框架,可以快速构建Web应用
  • 基于Electron框架,可以构建跨平台的桌面应用
  • 基于restify框架,可以快速构建API接口项目
  • 读写和操作数据库、创建使用的命令行工具辅助前端开发

内置API

fs文件系统模块
  • 读取文件
fs.readFile(path, options, callback); /**第一个参数为路径(必须) 第二个参数是可选参数,以什么编码格式来读取文件 第三参数是回调函数(必须)**/

code:

// 1.导入模块
const fs = require("fs");

// 2.调用fs.readFile()
// 参数1:文件存放路径
// 参数2:读取文件采用的编码格式
// 参数3:回调函数,拿到读取失败和成功的结构 err dataStr
fs.readFile("./file/data.txt", "utf-8", function (err, dataStr) {
    // 如果读取成功, 则err的值为null
    // 如果读取失败,则err的值为错误对象
    console.log(err);
    console.log("------");
    console.log(dataStr);
});

在这里插入图片描述

  • 写文件
fs.writeFile(path, data, options, callback); /**第一个参数为路径(必须) 第二个参数是写入的数据, 第三个参数以什么编码格式来读取文件(可选) 第四个参数是回调函数(必须)**/

code:

const fs = require("fs");
// 参数1:文件存放路径
// 参数2:要写入的内容
// 参数3:可选参数以什么样的格式写入默认utf-8
// 参数4:回调函数
fs.writeFile("./file/data.txt", "hello node!!!", function (err) {
	// 注意:
	// 默认是直接覆盖原文件的数据
	// 只能创建文件,不能创建目录
    console.log(err);
});
  • 动态路径
  • __dirname : 表示当前目录
fs.readFile(__dirname + "/file/data.txt", function (err, data) {
    console.log(err);
    if (!err) {
        console.log(data);
    }
});
  • path.join() 方法
    注意他可以解析…/也就是如果拼接这个路径会向上返回一层路径,所以我们在拼接路径是尽量使用join方法,加号是直接拼接, 不会解析…/也不会解析./
const path = require("path");
path.join("/file", "/data.txt");
  • path.basename() 获取文明名,含后缀
const path = require("path");
const filePath = "demo/index.html"
const fullName = path.basename(filePath)
console.log(fullName);
// 如果移除后缀名
path.basename(filePath, ".html"); // 输出结果为index

在这里插入图片描述

  • path.extname()
const path = require("path");
const filePath = "demo/index.html"
const fullName = path.extname(filePath) // 输出结果为.html
http模块

用于创建web服务器的模块,通过http模块提供的http.createServer()方法,就能方便的把一台普通的电脑,变成一台web服务器,从而对外提供web资源服务。
code:

// 导入http 模块
const http = require("http");
// 创建服务器
const server = http.createServer();
// 为服务器绑定一个事件处理方法,监听客户端的请求
server.on("request", (req, res) => {
    // req 为请求对象,它包含了与客户端相关的数据和属性例如:req.url 是客户端请求的URL地址
    // req.method 是客户端 method 请求类型
    console.log(req.url, req.method);
    const str = `hello server ${req.method}`
    // res 响应对象,可以响应请求给用户端响应数据
    res.end(str);
})
// 服务器占用端口
// 占用端口   启动成功的回调函数
server.listen("8888", () => {
    console.log("server is running at 127.0.0.1:8888");
})

在这里插入图片描述
这里我没响应的英文字符如果有中文会乱码,需要在响应对象上设置编码格式。

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

根据客户端不同请求路径返回不同的数据:
code:

// 导入http 模块
const http = require("http");
const { url } = require("inspector");

// 创建服务器
const server = http.createServer();

// 为服务器绑定一个事件处理方法,监听客户端的请求
server.on("request", (req, res) => {

    const url = req.url;
    console.log(url);
    // 根据不同的url返回不同的内容
    let content = "<h1>404 not found</h1>";
    if (url === "/" || url === "/index.html") {
        content = "<h1>首页</h1>"
    } else if (url === "/about") {
        content = "<h1>关于页面</h1>"
    }
    res.setHeader("Content-Type", "text/html;charset=utf-8")
    res.end(content);
})

server.listen("8888", () => {
    console.log("server is running at 127.0.0.1:8888");
})

将请求路径映射为文件路径:

// 导入http 模块
const http = require("http");
const fs = require("fs");
const path = require("path");
// 创建服务器
const server = http.createServer();
server.on("request", (req, res) => {
    const url = req.url;
    // 拼接文件路径
    const filePath = path.join(__dirname, url);
    console.log(filePath);
    fs.readFile(filePath, "utf-8", function (err, data) {
        if (!err) {
        	// 这边暂时不设置请求头,也可以判断请求url设置
            res.end(data);
        }
    })
})
server.listen("8888", () => {
    console.log("server is running at 127.0.0.1:8888");
})

文件结构如下:
在这里插入图片描述

如下图果结果可以看到在index.html引用的外部css文件和js文件会自动发请求去请求
在这里插入图片描述

Node 模块化

1 node.js中模块分为三大类:

  • 内置模块(例如fs,http, path)
  • 自定义模块(用户创建的每个js文件, 都是自定义模块)
  • 第三方模块(非官方提供,第三方开发的模块)

2 加载模块

const fs = require("fs")  // 内置模块
const custom = require("./custom.js") // 自定义模块
const moment = require("moment"); // 第三方模块

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

3 模块作用域
在js中如果两个文件定义了同一个var变量,引入的时候会造成变量污染。在Node.js中模块作用域可以避免这个问题。

var uerName = "ly";
function syHello() {
    console.log(uerName);
}

引入自定义模块

const custom = require('./other.js')
console.log(custom)

运行结果可见模块内的变量不能被外部使用:
在这里插入图片描述
那么这时候就要问了,外面怎么使用模块总的属性和方法呢?
4 模块化的使用

  • module
    在每个.js自定义模块中都有一个module对象,里面存储了和当前模块有关的信。
console.log(module); // 所以变量名最好不要用这个名字

在这里插入图片描述
exports : 向外共享成员

const age = 20;
module.exports.userName = "ly"
module.exports.syHello = function syHello() {
    console.log(uerName);
}
// 暴露的另一种方式
module.exports.age = age;

引入自定义模块

const custom = require('./other.js')
console.log(custom)

简写形式

// 可以省略module
const age = 20;
exports.userName = "ly"
exports.syHello = function syHello() {
    console.log(uerName);
}
// 暴露的另一种方式
exports.age = age;

运行结果如下,现在就可以访问自定义模块的成员了:
在这里插入图片描述
注意:
暴露的成员永远是module.exports指向的对象

const age = 20;
module.exports.userName = "ly"
module.exports.syHello = function syHello() {
    console.log(uerName);
}
// 暴露的另一种方式
module.exports.age = age;

module.exports = {
    newName : 'zwb',
    syHi: function(){
        console.log("zwb nb!");
    }
}

运行结果,可见上面的暴露被覆盖,真正暴露的是下面的对象:
在这里插入图片描述
CommonJS规范:

  • 每个模块,module变量代表当前模块。
  • module变量是一个对象,它的exports属性是对外的接口。
  • 加载某个模块其实是加载了该模块的module.exports属性。

NPM与包

Node.js中的第三方模块就是包。npm官网有很多开源包https://www.npmjs.com/

安装包,安装相关信息会记录到package.json文件里

npm i 包名     //  安装包
npm i 包12 //  一次性安装多个包
npm i // 安装所有包
npm i 包名 -D // 开发依赖包,会被记录到devDependencies
npm i -g // 全局包,一般是安装工具包

初始化,包管理配置文件package.json,注意路径不要有中文。

npm init -y

express框架

1 基础
它是一个基于nodejs开发的web服务器开发框架。
官方:

https://expressjs.com/zh-cn/

安装

npm i express@4.17.1 

2 实战

  • 创建一个服务器
// 导入express
const express = require("express")
// 创建web服务器
const app = express()
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})
  • 响应客户端的请求
// 导入express
const express = require("express")
// 创建web服务器
const app = express()
// 监听客户端的请求
// get
app.get("/usr", (req, res) => {
    // 调用express提供的res.send()方法响应一个方json对象,res.send()可以发送一个json也可以发送普通的文本
    res.send({
        name: "ly",
        age: "25"
    })
})
// post
app.post("/usr", (req, res) => {
    // 调用express提供的res.send()方法响应一个方json对象
    res.send("请求成功!!!")
})
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})
  • 获取URL携带的参数
    1)获取?参数
app.get("/", (req, res) => {
    // 通过req.query 可以获取到客户端发送过的参数
    console.log(req.query);
    res.send(req.query);
});

请求127.0.0.1:8888/?name=ly&age=18, 结果为:
在这里插入图片描述
2)获取动态参数

app.get("/demo/:id", (req, res) => {
    // 通过req.query 可以获取到客户端发送过的参数
    console.log(req.params);
    res.send(req.params);
});
// 可以携带多个parms参数/demo/:user/:age/:salary

请求127.0.0.1:8888/demo/2,运行结果:
在这里插入图片描述

  • 静态资源托管
    expres.static()
// 导入express
const express = require("express")
// 创建web服务器
const app = express()

// 将static作为静态资源向外提供

app.use(express.static("./static"))

// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

目录结构:
在这里插入图片描述
运行结果:
在这里插入图片描述在这里插入图片描述
注:Express在指定的静态目录总查找文件,并对外提供资源的访问路径。因此平台文件的目录不会出现在URL中,可以看到我们请求资源的时候并没有加static路径。托管多个静态资源目录,多次调用app.use(express.static(“./static”))即可,他会按照目录的加载顺序查找所需的文件。

// 导入express
const express = require("express")
// 创建web服务器
const app = express()
// 将static和file作为静态资源向外提供
app.use(express.static("./static"))
app.use(express.static("./file"))
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

目录结构:
在这里插入图片描述
访问http://127.0.0.1:8888/index.html,结果:
在这里插入图片描述
如果交换file和static的顺序:
在这里插入图片描述
如果需要添加访问路径,按下面的方式即可:

// 如果需要加访问路径
app.use("static", express.static("./static")); // 这样就需要访问127.0.0.1:8888/static/index.html
  • express 路由
    express中的路由3部分组成,分别是请求类型、请求URL地址、处理函数。
    1)简单用法
// 挂载路由,直接挂载到app上,不推荐
app.get("/usr", (req, res) => {
    res.send("demo");
})

2)模块化路由
定义路由模块

const express = require("express");
// 创建路由对象
const router = express.Router();
// 挂载路由
router.get("/usr", (req, res) => {
    res.send("getUserList")
})
router.post("/usr/add", (req, res) => {
    req.send("post add user sucess")
})
// 导出路由
module.exports = router

使用路由

// 导入express
const express = require("express");
// 导入router
const router = require("./router");
// 创建web服务器
const app = express()
// 注册路由
app.use(router)
// 如果需要加访问路径127.0.0.1:8888/api/usr
// app.use("/api",router) 这样访问的时候就需要
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})
  • express中间件
    可以对请求进行预处理,其本质就是一个function处理函数。
// 导入express
const express = require("express");
// 导入router
const router = require("./router");
// 创建web服务器
const app = express()
// 中间件函数
const mw = function (req, res, next) {
    console.log("中间件函数!!!");
    // 一定要放行
    next();
}
// mw注册为全局的中间件,也可以直接放一个函数在use里面不用定义额外的变量
// 如果定义了多个中间件函数,会按照use的顺序执行
app.use(mw)
// 注册路由
app.use(router)

// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

这样每个请求都会先走中间件函数,在这个函数里可以对请求进行一些处理。比如我们需要每个请求到达服务器的时间:

// 导入express
const express = require("express");
// 导入router
const router = require("./router");
// 创建web服务器
const app = express()
// 中间件函数
app.use( (req, res, next) => {
    const time = Date.now();
    // 将时间赋值到req中
    req.startTiem = time;
})
// 注册路由
app.use(router)
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

如果需要定义一个局部的中间件,即只对某些特定请求生效。

// 导入express
const express = require("express");
// 导入router
const router = require("./router");
// 创建web服务器
const app = express()
// 局部中间件函数
const jubu = (req, res, next) => {
    console.log("调用局部中间件!!");
    const time = Date.now();
    req.startTiem = time;
    next()
}
// 这样这个中间件就只会在当前请求生效
app.get("/test", jubu, (req, res) => {
    res.send("200");
});
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

在路由中使用多个局部中间件
定义中间件

const m1 = (req, res, next) => {
    console.log("我是中间件1!!");
    next();
}

const m2 = (req, res, next) => {
    console.log("我是中间件2!!");
    next();
}
module.exports = {
    m1,
    m2
}

使用

const express = require("express");
const { m1, m2 } = require("./media")
// 创建路由对象
const router = express.Router();

// 挂载路由,中间件的写法也可以直接写m1,m2
router.get("/usr", [m1, m2], (req, res) => {
    res.send("getUserList")
})
router.post("/usr/add", [m1, m2], (req, res) => {
    req.send("post add user sucess")
})
// 导出路由
module.exports = router

注:
一定要在路由之前使用中间件函数
一定要调用next函数,并且在next后面不要在写额外的代码

中间件的分类
1)应用级别的中间件;通过app.use(),app.get(), app.post()绑定到app实例上。
2)路由级别的中间件;绑定到express.Router()实例上的中间件。
3)错误级别中间;错误级别的中间件必须有4个参数分别是(err, req, res, next)。

// 导入express
const express = require("express");
// 导入router
const router = require("./router");
// 创建web服务器
const app = express()
app.use(router);
// 注册全局错误级别中间件,注意它必须注册在路由之后,其它的中间件要注册到路由之前
app.use((err, req, res, next) => {
    console.log(err);
    if (err) {
        res.send("发生错误");
    }
    next();
})
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

4)内置中间件express.static();express.json()解析JSON格式的请求体数据(在4.16.0+的版本可用);express.urlencoded()解析URL-encoded格式的请求体数据(在4.16.0+的版本可用)

// 配置表单解析的中间件,如果不配置req.body默认为undifined
app.use(express.json());
// 解析express.urlencoded()数据
app.use(express.urlencode({extended:false});

在这里插入图片描述
5)第三方中间件
安装,require,app.use()三步走即可。

自定义中间件

// 导入express
const express = require("express");
// 导入router
const router = require("./router");
const qs = require("querystring")
// 创建web服务器
const app = express()
// 自定义中间件,做一下数据的处理,中间件都是共享req和res
app.use((req, res, next) => {
    let str = ""
    // 监听data事件每次接收到的数据,乳沟数据过多可能会触发多次
    req.on("data", chunk => {
        str += chunk
    })
    // 监听end事件,数据已经发送完毕,接着进一步处理
    req.on("end", () => {
        console.log(str);
        // 解析数据
        const body = qs.parse(str)
        // 将数据挂载到body
        req.body = body;
        console.log(body);
        // 流转到下一步骤(中间件或路由)继续处理
        next();
    })
})
  • express跨域问题
    1)安装cros
npm i cros

2)配置

// 导入express
const express = require("express");
// 路由之前配置跨域
app.use(cros())
// 创建web服务器
const app = express()
// 启动服务器
app.listen(8888, () => {
    console.log("server is running at 8888");
})

msql模块

1)安装模块

npm i mysql

2)crud操作
查询数据

const mysql = require("mysql");
const db = mysql.createConnection({
    host: 'ip',
    user: 'root',
    password: '654321',
    database: "user_center",
    port: "3306"
})
db.connect();
db.query("select * from user", (err, results) => {
    if (err) return console.log(err.message);
    console.log(results);
})

在这里插入图片描述
插入数据

const mysql = require("mysql");

const db = mysql.createConnection({
    host: 'ip',
    user: 'root',
    password: '123456',
    database: "user_center",
    port: "3306"
})
db.connect();
// ?占位后面执行sql语句的时候赋值
const sql = "insert into stu (name,age) values (?, ?)"
// 执行语句的时候赋值
db.query(sql, ["ly", 25], (err, results) => {
    if (err) return console.log(err.message);
    console.log(results);
})

在这里插入图片描述
更新数据

const mysql = require("mysql");

const db = mysql.createConnection({
    host: 'ip',
    user: 'root',
    password: '654321',
    database: "user_center",
    port: "3306"
})
db.connect();
// ?占位后面赋值
const sql = "update stu set age=? where name=?"
// 执行语句的时候赋值
db.query(sql, [18, 'ly'], (err, results) => {
    if (err) return console.log(err.message);
    console.log(results);
})

在这里插入图片描述
注意:在插入和更新操作的时候?插入或更新的时候,如果对象和表一一对应的话就可直接写对象。
插入

const stu = { name: 'ly', age: 20 };
const sql = "insert into stu set ?"
// ?用对象
db.query(sql, stu, (err, results) => {
    if (err) return console.log(err.message);
    console.log(results);
})

更新

const stu = { name: 'wb', age: 20 };
const sql = "update stu set ? where name=?"
// ?用对象
db.query(sql, [stu, 'ly'], (err, results) => {
    if (err) return console.log(err.message);
    console.log(results);
})

删除数据

const stu = { name: 'wb', age: 20 };
const sql = "delete from stu where name=?"
// ?用对象
db.query(sql,  'ly', (err, results) => {
    if (err) return console.log(err.message);
    console.log(results);
    
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值