一、搭建简易服务器
1. 初始搭建
// 0. 引入内置模块
const http = require("http");
const fs = require("fs");
const url = require("url");
const path = require("path");
// 1. 创建一个服务器
const server = http.createServer((req, res) => {
const { query, pathname } = url.parse(req.url, true);
if (/^\/views/.test(pathname)) {
const { base } = path.parse(pathname);
fs.readFile("./client/views/" + base, "utf-8", (err, data) => {
if (err) {
return fs.readFile('./client/views/404.html', 'utf-8', (err, data) => res.end(data))
}
res.end(data);
});
}
});
// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));
2. 配置 css
// 0. 引入内置模块
const http = require("http");
const fs = require("fs");
const url = require("url");
const path = require("path");
// 1. 创建一个服务器
const server = http.createServer((req, res) => {
const { query, pathname } = url.parse(req.url, true);
// console.log(pathname);
// 处理 html 结构
if (/^\/views/.test(pathname)) {
const { base } = path.parse(pathname);
fs.readFile("./client/views/" + base, "utf-8", (err, data) => {
if (err) {
return fs.readFile(
"./client/views/404.html",
"utf-8",
(err, data) => res.end(data)
);
}
res.end(data);
});
}
/**
* 处理 css 样式
*
* 要求请求css的时候, 以 /style 开头
* 后续跟上要请求的文件
*/
if (/^\/style/.test(pathname)) {
const { base } = path.parse(pathname);
fs.readFile('./client/css/' + base, 'utf-8', (err, data) => {
if (err) return console.log(err)
res.end(data)
})
}
});
// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));
3. 接口和静态资源
// 0. 引入内置模块
const http = require("http");
const fs = require("fs");
const url = require("url");
const path = require("path");
// 1. 创建一个服务器
const server = http.createServer((req, res) => {
const { query, pathname } = url.parse(req.url, true);
/**
* 问题:
* 目前的方式中, 我们处理了 html css
* 但是还有很多 静态资源没有处理 (js, img, 音视频.....)
*
*
* 按照我们目前的方式处理, 最终代码一定会很多, 并且 其中有很多代码是重复代码
*
*
* 所以我们之前的解决方式, 仍不足以满足工作中的需求
* 那么我们做一个新的约定
*
* 如果前端需要访问 index.html
* 请求的路径 /static/index.html
* 如果前端需要访问 login.js
* 请求的路径 /static/login.js
* 如果前端需要访问 list.css
* 请求的路径 /static/list.css
*
* 其实就是请求的时候 统一以 /static 开头, 后续跟上我们需要请求的文件名
*/
if (/^\/static/.test(pathname)) {
const { base, ext } = path.parse(pathname);
let urlStr = "./client/";
if (ext === ".html") {
urlStr += "views/";
} else if (ext === ".css") {
urlStr += "css/";
} else if (ext === ".js") {
urlStr += "js/";
}
fs.readFile(urlStr + base, "utf-8", (err, data) => {
if (err) {
if (ext === ".html") {
return fs.readFile(
"./client/views/404.html",
"utf-8",
(err, data) => {
console.log(data);
res.end(data);
}
);
} else {
return res.end("");
}
}
res.end(data);
});
}
// 处理 html 结构
// if (/^\/views/.test(pathname)) {
// const { base } = path.parse(pathname);
// fs.readFile("./client/views/" + base, "utf-8", (err, data) => {
// if (err) {
// return fs.readFile(
// "./client/views/404.html",
// "utf-8",
// (err, data) => res.end(data)
// );
// }
// res.end(data);
// });
// }
// 处理 css 样式
// if (/^\/style/.test(pathname)) {
// const { base } = path.parse(pathname);
// fs.readFile("./client/css/" + base, "utf-8", (err, data) => {
// if (err) return console.log(err);
// res.end(data);
// });
// }
});
// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));
4. 添加接口处理
// 0. 引入内置模块
const http = require("http");
const fs = require("fs");
const url = require("url");
const path = require("path");
// 1. 创建一个服务器
const server = http.createServer((req, res) => {
const { query, pathname } = url.parse(req.url, true);
// 1.1 静态资源配置 (html, css, js, img, video, mp4...)
if (/^\/static/.test(pathname)) {
const { base, ext } = path.parse(pathname);
let urlStr = "./client/";
if (ext === ".html") {
urlStr += "views/";
} else if (ext === ".css") {
urlStr += "css/";
} else if (ext === ".js") {
urlStr += "js/";
}
fs.readFile(urlStr + base, "utf-8", (err, data) => {
if (err) {
if (ext === ".html") {
return fs.readFile(
"./client/views/404.html",
"utf-8",
(err, data) => {
console.log(data);
res.end(data);
}
);
} else {
return res.end("");
}
}
res.end(data);
});
}
// 1.2 处理接口数据 (用户详情, 首页轮播图, 商品列表...)
if (/^\/api/.test(pathname)) {
// 如果当前分支执行, 说明前端发了一个请求, 想要获取某个数据, 此时我们应该严格对比请求的地址和方式, 然后对前端的请求做出响应
// console.log(pathname)
// 商品列表数据
if (pathname === '/api/goods/list' && req.method === 'GET') {
// 1. 获取前端携带的参数
// 2. 根据前端携带的参数, 去数据库中 寻找对应的数据
// 3. 将处理完毕的数据, 返回给前端
const list = [
{
id: 1,
name: '商品1'
},
{
id: 2,
name: '商品2'
},
{
id: 3,
name: '商品3'
}
]
// res.end(list) // 直接返回数组 会报错
// res.end('返回了一个字符串, 看看会不会报错') // 返回字符串没有问题
// 所以我们将 非字符串的数据, 转换成 JSON 格式的数据 返回, 就不会有报错了
// res.end(JSON.stringify(list))
// 开发中后端返回数据一般是对象格式, 对象中 code 就是证明本次请求是否成功
res.end(JSON.stringify({
code: 1,
msg: '商品列表请求成功',
// list: list
list
}))
}
// 商品详情
if (pathname === '/api/goods/info' && req.method === 'POST') {
// 1. 获取前端携带的参数
// 2. 根据前端携带的参数, 去数据库中 寻找对应的数据
// 3. 将处理完毕的数据, 返回给前端
res.end(JSON.stringify({
code: 1,
msg: '商品详情请求成功',
info: {
id: 'qf001',
name: '商品的名字',
title: '商品的标题',
price: '$100.00'
}
}))
}
// 目前我们已经成功的处理了 前端发送的 ajax 请求, 但是我们没有处理对应的传参; 思考: get 的参数, 如何处理?
}
});
// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));
5. 处理接口参数
// 0. 引入内置模块
const http = require("http");
const fs = require("fs");
const url = require("url");
const path = require("path");
// 1. 创建一个服务器
const server = http.createServer((req, res) => {
const { query, pathname } = url.parse(req.url, true);
// 1.1 静态资源配置 (html, css, js, img, video, mp4...)
if (/^\/static/.test(pathname)) {
const { base, ext } = path.parse(pathname);
// console.log(path.parse(pathname))
let urlStr = "./client/";
if (ext === ".html") {
urlStr += "views/";
} else if (ext === ".css") {
urlStr += "css/";
} else if (ext === ".js") {
urlStr += "js/";
}
fs.readFile(urlStr + base, "utf-8", (err, data) => {
if (err) {
if (ext === ".html") {
return fs.readFile(
"./client/views/404.html",
"utf-8",
(err, data) => {
res.end(data);
}
);
} else {
return res.end("");
}
}
res.end(data);
});
}
// 1.2 处理接口数据 (用户详情, 首页轮播图, 商品列表...)
if (/^\/api/.test(pathname)) {
// 商品列表数据
if (pathname === "/api/goods/list" && req.method === "GET") {
// 1. 获取前端携带的参数
// 2. 根据前端携带的参数, 去数据库中 寻找对应的数据
// 3. 将处理完毕的数据, 返回给前端
res.end(
JSON.stringify({
code: 1,
msg: "商品列表请求成功",
list: [
{
id: 1,
name: "商品1",
},
{
id: 2,
name: "商品2",
},
{
id: 3,
name: "商品3",
},
],
})
);
}
// 商品详情
if (pathname === "/api/goods/info" && req.method === "POST") {
// 1. 获取前端携带的参数
// 2. 根据前端携带的参数, 去数据库中 寻找对应的数据
// 3. 将处理完毕的数据, 返回给前端
res.end(
JSON.stringify({
code: 1,
msg: "商品详情请求成功",
info: {
id: "qf001",
name: "商品的名字",
title: "商品的标题",
price: "$100.00",
},
})
);
}
// 登录
if (pathname === "/api/user/login" && req.method === "POST") {
/**
* 1. 接收用户传递的参数
*
* 在我们的请求报文中有一个方法
*
* req.on()
*
* 语法1:
* req.on('data', (chunk) => { console.log(chunk 就是请求头内传递的参数, 但是可能会分多次传递) })
*
* 我们请求体内的参数会分为多次传递到上边的回调函数内的形参 chunk 中
* 至于什么时候接收完毕, 我们不知道, 因为上述的代码可能会执行多次
*
* 所以这个方法还有一个 语法2, 会在 请求体内的参数接收完毕的时候, 执行
* 语法2:
* req.on('end' () => { console.log(当前回调函数会在请求体内的参数接收完毕的时候执行) })
*/
let dataStr = "";
req.on("data", (chunk) => {
dataStr += chunk;
});
req.on("end", () => {
// console.log("我需要等到参数接收完毕的时候 在执行", dataStr);
// 当前回调函数执行的时候, dataStr 其实就是我们的 参数
/**
* 一个新的问题:
* 此时的参数 dataStr 是 查询字符串 还是 JSON 格式的字符串?
*
* 现在有一个 世界约定
* 我们在开发的时候 前端如果是 POST 方式, 并且需要携带参数
* 那么需要在 请求头内 设置 content-type 属性
* 目的就是为了告诉后端, 当前的参数格式是什么
*/
if (req.headers["content-type"] === "application/json") {
dataStr = JSON.parse(dataStr);
}
if (
req.headers["content-type"] ===
"application/x-www-form-urlencoded"
) {
dataStr = url.parse("?" + dataStr, true).query;
}
// 2. 安全校验 (非空, 是否符合正则规则)
if (dataStr.username === "" || dataStr.password === "") {
// 账号或密码 传递的是空字符
}
if (
dataStr.username === undefined ||
dataStr.password === undefined
) {
// 账号或密码 没有传递
}
const nameReg = /^[a-z0-9]\w{4,11}$/;
const pwdReg = /^\w{6,12}$/;
if (
!nameReg.test(dataStr.username) ||
!pwdReg.test(dataStr.password)
) {
// 账号或密码 格式不对
}
// 3. 根据用户传递的参数, 去数据库中查询是否有对应的用户
// 4. 根据查询的结果, 反馈不同的信息
res.end(
JSON.stringify({
code: 1,
msg: "登录成功",
token: "后端需要返回一个 token, 将来前端会利用 token 证明登陆过, 并且在有效期内",
})
);
});
}
// 购物车列表
if (pathname === "/api/cart/list" && req.method === "GET") {
/**
* 因为 get 方式 只允许传递 查询字符串, 所以在当前服务器一开始的时候就已经将当前请求的 参数 解析完毕
*
* 其实当前服务器最开始的第一行代码: const { query, pathname } = url.parse(req.url, true);
*/
console.log(query);
res.end(JSON.stringify({
code: 1,
msg: '购物车列表获取成功',
list: '这是一个数组'
}))
}
}
});
// 2. 给服务器添加一个端口号
server.listen(8080, () => console.log("服务器启动成功"));