客户端和服务器之间的通信可简单的理解为:客户端“请求”,服务器“响应”,一来一回就可以达成信息的传递。在浏览器客户端,可通过js(XMLHttpRequest)发起请求,在服务器端(nodeJS为例)中则是通过net或者http模块发送信息。
net模块
nodejs.org/dist/latest…
net模块对应TCP/IP协议,连接建立后后可发送任意形式的信息,只要通信双方约定好信息的格式,就能解读出发送的信息,是一种比较底层的通信使用方法。
客户端
const net = require("net");
// 第一步,与服务器建立连接
const socket = net.createConnection({
// socket是一个stream对象,向其“write”则发送信息,监听“data”事件则可获取信息
host: "baidu.com",
port: 9527,
}, () => {
console.log("连接成功");
});
// 第二步,发送请求
socket.write('需要发送的信息');
// net模块是一种比较底层的通信模块,就是单纯的发送信息,获取信息。如果需要进行http通信,则需要发送http格式的信息。
socket.write('GET / HTTP/1.1
Host: baidu.com
Connection: keep-alive
');
// 第三部,获取响应数据
socket.on('data', (chunk) => {
console.log(chunk);
});
服务器端
const net = require("net");
const server = net.createServer();
// 监听9527端口
server.listen(9527);
server.on('listening', () => {
console.log('开始监听9527端口');
});
server.on('connection', (socket)=> {
console.log("客户端连接完成");
socket.on('data', (chunk) => {
console.log('客户端发来的信息', chunk.toString('utf-8'));
const Buf = Buffer.from(`HTTP/1.1 200 OK
Content-Type: image/jpeg
你好
`, 'utf-8');
socket.write(Buf);
socket.end();
});
});
http通信是建立在TCP/IP协议基础上的,实际就是客户端发送固定格式的字符串,服务端收到信息,解析信息,将响应信息以相同格式发回客户端。
http模块
nodejs.org/dist/latest…
http模块对应http协议,http模块专门用于发送http请求,比net模块便利很多。
客户端
const http = require('http');
// 客户端发送请求与ajax类似
const request = http.request("url", {
method: 'GET'
}, (resp) => {
// console.log('来自服务器的响应信息', resp);
console.log('响应头', resp.headers);
console.log('状态码', resp.statusCode);
let result = "";
resp.on('data', (chunk) => {
result += chunk.toString('utf-8');
});
resp.on('end', () => {
console.log(JSON.parse(result));
});
});
request.end(); //表示消息体结束
服务器端
const http = require('http');
const server = http.createServer(hanlder);
const server.listen(6100, () => {
console.log('端口监听完成');
);
const hanlder = function (req, res) {
console.log('客户端请求对象', req);
// 发送响应消息
res.write("hello");
res.end();
}
了解http模块的使用方法后,可搭建一个简单的静态资源服务器
// http模块搭建服务器 搭一个静态资源服务器
const path = require('path');
// const URL = require("url");
const http = require('http');
const fs = require('fs');
// 判断文件是否存在
async function getStat(filename) {
try {
return await fs.promises.stat(filename);
} catch {
return null;
}
}
async function getFileContent(url) {
// console.log();
// url.slice(1) 避免url一开始是'/',去到根目录
let filename = path.resolve(__dirname, 'public', url.slice(1));
let stat = await getStat(filename);
if (!stat) {
return null;
} else if (stat.isDirectory()) {
filename = path.resolve(__dirname, 'public', url.slice(1), 'index.html');
stat = await getStat(filename);
if (!stat) {
return null;
}
// return await fs.promises.readFile(filename);
return await fs.createReadStream(filename);
}
// return await fs.promises.readFile(filename);
return await fs.createReadStream(filename);
}
async function hanlder(req, res) {
const url = req.url;
// console.log(url);
// const result = await getFileContent(url);
const rs = await getFileContent(url);
if (rs) {
rs.pipe(res);
rs.on('close', () => {
res.end();
});
} else {
res.statusCode = 404;
res.write("Resource is not exist");
res.end();
}
// 若res.end()了,就不会触发drain事件(猜测所有Stream的事件应该都不触发)
// res.end();
}
// 每有一次请求来都会执行一次handler
const server = http.createServer(hanlder);
server.listen(6100, () => {
// console.log('端口监听完成');
});
server.on('listening', () => {
console.log('监听6100端口');
});