1 node.js 基本概念:
- 是一个基于chrome V8引擎的JavaScript运行环境,而不是编程语言,用来运行 js 代码。
- (学习node不是学习新语言,而是学习模块的使用)
2 node.js 和浏览器端的区别
- 相同点:都支持ECMAScript(变量、函数、运算。。。)
- 不同点:node.js没有window,bom,dom;浏览器也没有node.js中的模块
3 命令行下的按键和命令
4 node.js 中的模块分类
1. 核心模块(内置,自带):核心模块是node自带的,名字是固定的,不能乱写
1. 自定义模块(自己写的)
1. 第三方模块(别人写的)
5 核心模块–以 fs
- 使用
步骤:
1 引入
const 模块名=require('模块名')
2 调用
模块名.api( )
5.1 fs.readFile - 异步读文件
- 异步理解:
- 与 setTimeout() 一样会有异步效果,同步代码执行之后,再执行异步代码
- 读文件时,不一定取决于写代码的顺序,应取决于读文件的时间
// 引入
const fs = require('fs')
// 调用 fs.readFile(文件路径,编码格式, 回调函数) -->编码格式可写可不写
fs.readFile('hello.js','utf8', function (err, data) {
//err表示错误,如果读的过程中,有错误,则错误对象会保存在err中
if(err){
console.log(err)
return
// 尽早返回
//如果有错误,打印错误,停止执行
}
//data表示读出来的内容。如果不设置编码,它的类型是Buffer:16进制表示。如果设置了编码,则按编码规则进行转换
console.log(data)
})
5.2 fs.readFileSync - 同步读文件
// 引入
const fs = require('fs')
// 调用 fs.readFileSync(文件路径,编码格式) -->编码格式可写可不写
const content = fs.readFileSync('hllo.txt', 'utf8')
console.log(content);
5.3 捕获同步格式中的错误对象(使用try …catch…)
try {
const fs = require("fs")
let content = fs.readFileSync('文件路径',"utf8");
console.log(content)
} catch(err) {
console.log(err)
}
5.4 fs.writeFile - 覆盖写入
- 注意:
- 覆盖之前的内容
- 写入的内容必须时 string 或者 Buffer
- 写入数组或者对象,需转换成字符串 JSON.stringify()
// 引入
const fs = require('fs')
// 调用 fs.writeFile(文件路径,要写入的字符串,配置项,回调函数) -->配置项默认 utf-8
let arr = [1, 2, 3, 4, 5]
let arrStr = JSON.stringify(arr)
const fs = require('fs')
fs.writeFile('info.txt', arrStr, function (err) {
console.log('err为null,表示无错误,err:', err);
})
5.5 fs.appendFile - 追加写入
// 引入
const fs = require('fs')
// 调用 fs.appendFile(文件路径,要写入的字符串,配置项,回调函数) -->配置项默认 utf-8
const fs = require('fs')
// '\n'-->换行
fs.appendFile('hello.txt', '\n新添加的!', (err) => {
if (err) {
console.log('err', err);
}
})
6 路径问题–获取绝对路径
- 相对路径的隐患:在 fs 中读取文件时,如果采用相对路径,则读文件时,node.js 会去运行命令的路径+代码中的相对路径
- __dirname:获取当前被执行文件所在的文件夹的绝对路径
- __filename:获取当前被执行文件的绝对路径
7 核心模块 - path
- 作用:处理路径的相关方式
- 引入:const path = require(‘path’)
- 常用api:
- path.basename( ) //返回path的最后一部分,一般用来获取路径中的文件名。
- path.join( ) //路径拼接
- path.parse(pathurl) //把一个路径转成一个对象
path.basename('/foo/bar/baz/asdf/quux.html');// 返回: 'quux.html'
path.basename('/foo/bar/baz/asdf/quux.html', '.html');// 返回: 'quux'
path.dirname('/foo/bar/baz/asdf/quux');// 返回: '/foo/bar/baz/asdf'
path.extname('index.html');// 返回: '.html'
8 核心模块 - querystring
const qs = require('querystring')
let arr = 'name=李白'
const queryStr = qs.parse(arr)
console.log(queryStr);
// [Object: null prototype] { name: '李白' }
console.log(queryStr.name);
// 李白
9 服务器相关概念
-
服务器与客户端
1 服务器 = 电脑 + 能提供服务的软件
2 客户端 = 电脑 + 享受服务的软件 -
服务器类型:根据提供的服务不同来分类
1 web 服务器
2 数据库服务器
3 ftp 服务器 -
ip 地址:唯一定位位置的编号
-
域名
1 是 ip 地址的别名
2 localhost 表示本机的域名 -
端口
1 计算机通过 IP地址 + 端口号 来进行通讯
2 不能共用 -
http 协议:约定浏览器与web服务器之间的通信规则
-
请求
1 请求行
2 请求头
3 请求体(get 类型没有请求体)
-
2 响应
1 响应行
2 响应头
3 响应体
10 写一个服务器
- res.end( ) 作用:
- 结束请求
- 设置响应体
- 参数只能是字符串或 buffer
- 在服务器端获取本次请求的url
req.url // 一定是以 / 开头的
// 引入 http 模板
const http = require('http')
// 创建服务
const server = http.createServer((req, res) => {
// req:request 本次请求
// res: response 本次响应
// 回调,每一次请求都会执行一次
res.end('只能是字符串或者buffer')
})
// 启动服务--指定端口
server.listen(端口号, () => {
console.log('启动成功');
})
11 content- type
- 作用:告诉浏览器本次传输的数据类型
- 在请求头(响应头)中起作用
- 格式:res.setHeader(‘content-type’, ‘xxxxxxx’)
.html:res.setHeader('content-type', 'text/html;charset=utf8')
.css:res.setHeader('content-type', 'text/css;charset=utf8')
.js: res.setHeader('content-type', 'application/javascript')
.png: res.setHeader('content-type', 'image/png')
json 数据: res.setHeader('content-type', 'application/json;charset=utf-8')
其它类型,参考这里:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
12 状态码:http 协议约定的编码
类型:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
常见状态码:200 、301 、400 、401 、404 、500
13 处理 html 文件中的二次请求
// 引入 http 模板
const http = require('http')
const fs = require('fs')
const path = require('path')
// 创建服务
const server = http.createServer((req, res) => {
// 获取 url
const { url } = req
// console.log(url);
// 如果地址为 / 或 index.html则返回 index.html
if (url === '/' || url === '/index.html') {
// 地址拼接
const pathFile = path.join(__dirname, 'index.html')
// 读文件,返回
const content = fs.readFileSync(pathFile, 'utf8')
res.end(content)
} else if (url === '/' || url === '/index.css') {
// 地址拼接
const pathFile = path.join(__dirname, '/index.css')
// 读文件,返回
const content = fs.readFileSync(pathFile, 'utf8')
res.end(content)
} else if (url === '/' || url === '/4.jpg') {
// 地址拼接
const pathFile = path.join(__dirname, '/4.jpg')
// 读文件,返回
const content = fs.readFileSync(pathFile)
res.end(content)
} else if (url === '/' || url === '/js/jquery.js') {
// 地址拼接
const pathFile = path.join(__dirname, '/js/jquery.js')
// 读文件,返回
const content = fs.readFileSync(pathFile)
res.end(content)
} else {
res.end('404')
}
14 统一处理静态资源
- 思路:收到请求后,在指定的文案夹下读资源:读到,返回(读不到,返回 404)
// 导入模板
const fs = require('fs')
const path = require('path')
const http = require('http')
// 创建服务器
const server = http.createServer((req, res) => {
// 取地址
const { url } = req
// console.log(url);
// 获取地址后缀
const map = path.extname(url)
// console.log(map);
// 后缀名对象
const contentMap = {
'.html': 'text/html;charset=utf-8',
'.css': 'text/css;charset=utf-8',
'.jpg': 'image/jpg',
'.js': 'application/javascript'
}
// 拼接地址
const pathFile = path.join(__dirname, 'public', url)
// console.log(pathFile);
try {
// 读文件
const content = fs.readFileSync(pathFile)
// 判断后缀
if (contentMap[map]) {
res.setHeader('content-type', contentMap[map])
}
res.end(content)
} catch (err) {
res.end('错了错了')
}
})
// 启动服务器
server.listen(8888, () => {
console.log('服务已启动,开始得瑟');
})
15 接口
-
三要素:
1 方式
2 url
3 请求参数 -
类型:get / post /…
-
get 请求和 post 请求的区别:
1.请求类型不同
2.请求携带参数不同
(1) get :参数是在 url 中拼接的,参数是通过请求行传递给后端,后端可以立即获取
(2)post :参数是请求体中传递给后端的(数据是一段一段传的)3.http 模块中获取参数
(1)get:req.url 中可以直接获取查询字符串;
(2)post:在 req 上添加两个事件- data 每次收到一段数据之后,就会触发一次
- end 全部接收完成之后,触发一次
写一个 get 类型的请求,返回 json 格式的数据
// 导入模板
const fs = require('fs')
const path = require('path')
const http = require('http')
// 创建服务器
const server = http.createServer((req, res) => {
// 取地址
const { url } = req
// console.log(url);
// 获取地址后缀
const map = path.extname(url)
// console.log(map);
// 后缀名对象
const contentMap = {
'.html': 'text/html;charset=utf-8',
'.css': 'text/css;charset=utf-8',
'.jpg': 'image/jpg',
'.js': 'application/javascript'
}
// 拼接地址
const pathFile = path.join(__dirname, 'public', url)
// console.log(pathFile);
try {
// 读文件
const content = fs.readFileSync(pathFile)
// 判断后缀
if (contentMap[map]) {
res.setHeader('content-type', contentMap[map])
}
res.end(content)
} catch (err) {
res.end('错了错了')
}
})
// 启动服务器
server.listen(8888, () => {
console.log('服务已启动,开始得瑟');
})
写一个 get 类型的请求,返回 json 格式的数据-带参数
// 引入模板
const http = require('http')
const path = require('path')
const fs = require('fs')
const qs = require('querystring')
// 创建服务器
const server = http.createServer((req, res) => {
// 当请求地址是 get 类型,并且是地址是 /getList 时,解析查询字符串
const [url, queryStr] = req.url.split('?')
// console.log(url, queryStr);
if (url == '/getList' && req.method === 'GET') {
// 把查询字符串转化成对象
const qsObj = qs.parse(queryStr)
// console.log(qsObj);
// 地址拼接
const pathFile = path.join(__dirname, 'db', 'data.json')
// console.log(pathFile);
// 设置 content-type
res.setHeader('content-type', 'application/json;charset=utf8')
// 读文件
const content = fs.readFileSync(pathFile, 'utf8')
// console.log(content);
// 内容转数组
const arr = JSON.parse(content)
// console.log(arr);
// 在数组中查找
const rs = arr.find(item => item.name === qsObj.name)
// 返回结果必须是字符串或者 buffer
const result = JSON.stringify(rs)
res.end(result)
} else {
res.end('404')
}
})
//启动服务器
server.listen(10086, () => {
console.log('服务器已启动,请开始得瑟');
})
写一个 post 类型的请求,添加数据
- 步骤:
- 添加事件监听,获取查询字符串格式数据
- 将接收到的数据转化为对象
- 读文件,将文件转化为数组
- 将数据写入数组
- 写回 .json 文件中
// 引入模板
const http = require('http')
const path = require('path')
const fs = require('fs')
const qs = require('querystring')
// 创建服务器
const server = http.createServer((req, res) => {
// 当请求地址是 get 类型,并且是地址是 /getList 时,解析查询字符串
const [url] = req.url.split('?')
// console.log(qsObj);
// 地址拼接
const pathFile = path.join(__dirname, 'db', 'data.json')
// console.log(pathFile);
if (url == '/add' && req.method === 'POST') {
// 添加事件监听
let result = ''
req.on('data', (chunk) => {
// console.log("每上传一小段触发一次", chunk);
result += chunk
})
req.on('end', () => {
// console.log('结束时才触发一次');
// 将查询字符串转化为对象
const qsObj = qs.parse(result)
// console.log(qsObj);
// 读文件
const content = fs.readFileSync(pathFile, 'utf8')
// console.log(content);
// 将文件转化为数组
const arr = JSON.parse(content)
// console.log(arr);
// 插入数据
arr.push({ name: qsObj.name })
// console.log(arr);
// 写回数据
fs.writeFileSync(pathFile, JSON.stringify(arr))
})
res.end('404')
} else {
res.end('404')
}
})
//启动服务器
server.listen(10086, () => {
console.log('服务器已启动,请开始得瑟');
})
16 模块化及发展
1 模块化:一个 js 文件可以引入另一个 js 文件中的方法
2 发展:es5不支持,es6支持,node.js支持()语法与es6中模块化语法有不同
17 自定义模块的使用背景和用法
- 背景: 代码重用 / 优化代码结构
- 步骤:
-
定义模块:
1 写函数
2 导出:module.exports = 要导出的内容(一般会是一个对象) -
使用模块:
1 导入:const 模块名 = require(相对路径)
2 使用 :使用前 log 一下看内容
- 导出模块有两种方式
- module.exports = 要导出的内容
- export.xxx=xxx
- 两种方式都存在时,以 module.exports 为准