一、fs 模块
内置模块(built-in):node 的安装时已经内置了核心模块,不用我们制造,可以直接使用;
fs模块:file system 文件系统,文件读写模块,用于读写文件;
let fs = require('fs');
1. 异步读取文件
fs.readFile(fileName, option, callback)
- fileName: 文件名
- option: 以哪一种编码返回内容,默认的 buffer 类型的值,buffer 中存储的是二进制数据;所以一般设置为 utf8
- callback: 读取文件后执行的回调
fs.readFile('./text.txt', 'utf8', function (err, data) {
err // 读取失败的错误信息
data // 从文件中读取来的数据
console.log(data)
});
2. 同步读取文件
fs.readFileSync(fileName, options);
- fileName: 文件名
- options: 编码
- 该方法会返回同步读取到的内容
let content = fs.readFileSync('./text.txt', 'utf8');
console.log(content);
3. 异步写入(向文件中写)
fs.writeFile(path, data, option, callback)
- path 文件名(如果没有就创建一个文件)
- data 写入文件的数据
- option 文件编码
- callback 写入后执行的回调
fs.writeFile('1.js', 'console.log(`hello world`);','utf8', function (err, data) {
if (err) {
console.log(err);
} else {
console.log('写入成功')
}
});
4. 同步写入(向文件中写)
fs.writeFileSync(path, data, option)
- path 文件名及路径
- data 写入的数据
- option 写入的编码
fs.writeFileSync('../x.js', 'alert(`hello world`)', 'utf8');
5. 异步追加内容
fs.appendFile(path, data, option, callback);
- data 写入文件的数据
- option 文件编码
- callback 写入后执行的回调
fs.appendFile('./1.js', '\nfunction sum (a, b) {return a + b}', 'utf8', function (err, data) {
if (err) {
console.log(err);
} else {
console.log(data)
}
});
6. 同步追加内容
fs.appendFileSync(path, data, option);
- path 文件名及路径
- data 写入的数据
- option 写入的编码
fs.appendFileSync('../x.js', ';\n\rfunction minus(a, b) {return a - b}', 'utf8');
例子
// fs 模块:是 Node.js 内置的模块;fs (file system 文件系统) 用于文件读写;
let fs = require('fs');
// 1. 异步读取文件:
// __dirname 当前文件所处的路径,绝对路径
// __filename 当前文件的带绝对路径的文件名,并且带扩展名
// fs.readFile(带路径的文件名, 编码, callback)
fs.readFile('./1.txt', 'utf8', (err, data) => {
// 如果读取成功 err 是 null,如果读取失败 err 是对象;
// 如果文件读取成功,会把读到的数据传给 data,在回调函数中使用这个 data 就是使用读取来的数据;
if (err) {
// console.log(err);
// no such file or directory 没有这样一个文件或者文件夹;(导致报错的原因就是文件路径错误)
} else {
// console.log(data);
}
});
// 2. 同步读取文件:
// fs.readFileSync(带路径的文件名, 编码)
// 返回值是读取到内容;
// let data = fs.readFileSync('./1.txt', 'utf8');
// console.log(data);
// 修改文件:向文件中写入内容
// 3. 异步写入文件
// fs.writeFile(path, data, option, callback);
// path 文件名(如果没有这个文件会创建一个)
// data 要写入文件的内容
// option 文件编码
// callback 写入后执行的回调
let code = 'function sum (a, b) {return a + b}';
fs.writeFile('./a.js', code, 'utf8', (err, data) => {
// err 写入失败时是一个对象,写入成功是 null
if (err) {
console.log('写入失败');
// 一般写入文件失败是由于文件夹权限有问题
} else {
// console.log('写入成功');
}
});
// fs.writeFile() 是覆盖式写入,原文件中的内容会被覆盖掉;如果要追加的话,先把原来的文件内容读取出
// 来,然后再拼接上咱们要写入的内容,然后再一并写回去;
// 同步写入:
// fs.writeFileSync(path, data, option)
// path 文件名(含路径)
// data 写入文件的内容
// option 编码
// 同步写入没有返回值
let htmlStr = `<!DOCTYPE>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="发上等愿,结中等缘,享下等福">
<meta name="keywords" content="前端好,前端好个锤子">
<title>这是一个title标签</title>
<!--TDK 做SEO时要设置-->
</head>
<body>
<div>
这是一个划时代的app
</div>
</body>
<script>
alert('真香')
</script>
</html>`;
let wdata = fs.writeFileSync('../a.html', htmlStr, 'utf8');
console.log(wdata);
// 向文件中追加内容:
// 异步追加
// fs.appendFile(path, data, option, callback)
// path 文件名(含路径)
// data 写入文件的内容
// option 编码
// callback 追加后的回调
let code2 = '\n\rfunction minus(a, b) {return a - b}';
// \n 换行
// \n\r 空行
/*fs.appendFile('./b.js', code2, 'utf8', (err, data) => {
if (err) {
console.log(err);
} else {
console.log('追加成功');
}
});*/
// 同步追加
// fs.appendFileSync(path, data, option)
// 参数和异步相同
fs.appendFileSync('./b.js', code2, 'utf8');
二、http 模块
前端发起请求,获取数据,然后拿到数据渲染到页面中;后端(服务端),响应请求,发送数据
前后端通过 http 协议通信,前端通过 http 发请求,向服务器要数据;服务端处理 http 请求,通过 http 协议向客户端发送数据;
http 模块:http 是 Node.js 的内置模块;是用来处理客户端的 http 请求的
let http = require('http');
let fs = require('fs');
// 1. 处理客户端 http 请求,首先要创建一个服务;
// http.createServer() 创建一个服务
let server = http.createServer(function (request, response) {
// 具体的处理 http 请求的代码要写在这个回调函数中;只要客户端发送一个 http 请求,这个回调函数就会执行一次;
// request 请求对象 这个对象中包含了客户端的请求中所有的信息;
// response 响应对象 这个对象中包含了所有用来响应客户端所需要的方法和属性;
console.log('请求来了');
// 把 index.html 响应给客户端
// 首先我们需要把 index.html 读出来,然后把读取的结果作为响应内容发送给客户端;
fs.readFile(__dirname + '/index.html', (err, data) => {
if (err) {
response.end('读取失败')
} else {
response.end(data); // 向客户端发送响应数据
}
});
// 我们在响应客户端请求的时候,现在并没有判断客户端请求的是什么;当客户端收到 index.html 以后会解析 html,解析的时候遇到 script 标签,而 script 会再向服务器发送请求,而此时我们的服务只会响应 index.html 的内容,所以 script 收到的就是 index.html 的内容;
});
// 2. 服务还需要监听端口号(练习阶段不要使用3000以下)
// 端口的范围:0-65535
// server.listen (端口号, 监听端口成功执行的回调)
server.listen(8000, () => console.log('port 8000 is on'));
// 一个端口只能供一个服务监听,当前8000端口被 server 占用了,其他的服务就不能再用8000端口了;
写完脚本以后,还需要到命令行里启动这个服务:node 加文件名,然后去浏览器中访问:localhost:8000
为什么用 localhost?
因为正常的请求是访问 url ,然后 DNS 负责把 url 解析成 ip 地址,然后请求 ip 地址,但是服务器是运行在本地,本地的 ip 127.0.0.1,而 127.0.0.1 就是 localhost。
此时我们的电脑上既运行着客户端又运行着服务端;浏览器是客户端,用 node 启动的 js 脚本是服务端。修改了服务端的程序需要重启 server
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
</head>
<body>
<h1>这是index.html</h1>
<div>
<a href="/a.html">这是A页面</a>
</div>
<div><a href="/b.html">这是B页面</a></div>
</body>
</html>
三、url 模块
// url 模块也是 Node.js 的内置模块,是用来解析 url 的;
let http = require('http');
let url = require('url');
let fs = require('fs');
// 1. 创建一个服务
let server = http.createServer((req, res) => {
// console.log(req.url); 客户端请求的 url
// console.log(req.headers.cookie); 客户端带来的 cookie
let urlObj = url.parse(req.url, true); // url.parse() 解析请求 url 的方法,第二个参数传 true,把 url 问号传参格式化成一个对象,并在挂载在 query 属性上
console.log(urlObj);
// pathname 客户端请求的路径
// search 客户端问号传参的内容(带问号)
// query 客户端传递的查询字符串
});
// 2. 监听端口号
server.listen(8000, () => console.log('port 8000 is on'));
四、根据不同路径返回不同内容
// 根据请求的路径的不同返回不同的 html
// 获取当前的请求路径,读取路径对应的 html 然后返回给客户端即可;
let http = require('http');
let url = require('url');
let fs = require('fs');
// 1. 创建一个服务
let server = http.createServer((req, res) => {
// 1.1 解析 url
let urlObj = url.parse(req.url, true);
let { pathname } = urlObj;
// server 启动时所在的路径就是根目录 /
// /a.html -> 读取 /a.html 文件
// /b.html -> 读取 /b.html 文件
// console.log('pathname is ' + pathname);
// console.log(__dirname + pathname);
// 当我们访问 localhost:8000 时 pathname 是 / ,此时并没有 / 的html
// 加一个判断,判断 pathname 是不是/,如果是 / 就要读 index.html
let filePath = '';
if (pathname === '/') {
filePath = __dirname + '/index.html'
} else {
filePath = __dirname + pathname;
}
fs.readFile(filePath, function (err, data) {
if (err) {
res.end('NOT FOUND')
} else {
res.end(data);
}
})
});
// 2. 监听一个端口号
server.listen(8000, () => console.log('port 8000 is on'));
// 服务端响应如 html、css、js、图片等文件服务称为静态资源服务,html、css、js 等文件称为静态资源;
// 如果 pathname 类似 /home/help/search ,这种请求路径不是具体的文件,一般都是 ajax 接口;一般都是处理动态的请求,根据客户端传递的数据返回不同的内容;
a.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="/a.css">
</head>
<body>
<h1>
A
</h1>
<a href="/">返回首页</a>
<img src="/3.png" alt="">
<script src="/a.js"></script>
</body>
</html>
b.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>
B
</h1>
<a href="/">返回首页</a>
</body>
</html>
五、响应与 content-type
// Content-Type:
// 服务端在响应客户端的请求的时候要设置响应内容的内容类型,即 Content-type;当客户端收到服务端的响应内容后,会按照这个 Content-type 解析响应的内容;
// Content-type 是一个响应头;
let http = require('http');
let url = require('url');
let fs = require('fs');
let contentTypes = {
html: 'text/html',
css: 'text/css',
js: 'text/javascript',
png: 'image/png',
ico: 'image/x-icon'
};
// 1. 创建一个服务
let server = http.createServer((req, res) => {
// 1.1 解析url
let urlObj = url.parse(req.url, true);
let { pathname } = urlObj;
// 根据 pathname 里面的拓展名,判断到底内容类型是什么;.html -> text/html; .css -> text/css
// /a.html
// /a.css
// /a.js
// /3.png
// /
let extReg = /\.(\w+)/;
let types = extReg.exec(pathname); // 正则捕获,如果捕获到返回数组,捕获不到返回 null
if (types) {
let ext = types[1];
console.log(ext);
res.setHeader('Content-Type', contentTypes[ext]);
// res.setHeader(key, value); 设置响应头信息,key 和 value 都是字符串类型的;
}
let filePath = '';
if (pathname === '/') {
res.setHeader('Content-Type', contentTypes.html);
filePath = __dirname + '/index.html'
} else {
filePath = __dirname + pathname;
}
fs.readFile(filePath, function (err, data) {
if (err) {
res.end('NOT FOUND')
} else {
res.end(data);
}
})
});
// 2. 监听一个端口号
server.listen(8000, () => console.log('port 8000 is on'));
六、MIME 依赖包
// MIME : 多用途互联网邮件拓展;每种文件都有自己特有的 MIME 类型,这个类型就是在响应的时候需要设置的内容类型;
// mime 依赖包,是一个第三方的模块,其中包含了绝大多数的文件的 MIME 类型;
// 使用第三方的依赖包:
// 1. 安装 mime :yarn add mime --save
// 2. 引入第三方的模块
let mime = require('mime');
let http = require('http');
let url = require('url');
let fs = require('fs');
let server = http.createServer((req, res) => {
// 1.1 解析 url
let urlObj = url.parse(req.url, true);
let { pathname } = urlObj;
// 使用 mime 设置内容类型:mime.getType(pathname)
// getType 方法会返回 pathname 对应的内容类型
let filePath = '';
if (pathname === '/') {
filePath = __dirname + '/index.html';
res.setHeader('Content-Type', 'text/html'); // mime.getType() 不能处理 / ;所以需要单独设置
} else {
filePath = __dirname + pathname;
res.setHeader('Content-Type', mime.getType(pathname));
}
fs.readFile(filePath, function (err, data) {
if (err) {
res.end('NOT FOUND')
} else {
res.setHeader('set-cookie', 'name=mabin;path=/;'); // 在服务端操作 cookie;就是设置 set-cookie 的响应头
res.end(data);
}
})
});
// 2. 监听一个端口号
server.listen(8000, () => console.log('port 8000 is on'));