静态服务器
定义
静态网页是指存放在服务器文件系统中实实在在的HTML文件。当用户在浏览器中输入页面的URL,然后回车,浏览器就会将对应的html文件下载、渲染并呈现在窗口中。早期的网站通常都是由静态页面制作的
原理
url时,这个url可能对应服务器上的一个资源(文件)也可能对应一个目录。
因此服务器会对这个url进行分析,针对不同的情况做不同的事。如果这个url对应的是一个文件,那么服务器就会返回这个文件。如果这个url对应的是一个文件夹,那么服务器会返回这个文件夹下包含的所有子文件/子文件夹的列表。同时我们在获取到后缀之后就可以根据后缀来设置它的ContentType
实例代码1
console.log(
"大哥,有人过来询问qq.com的路径啦!路径(带查询参数)为:" + pathWithQuery
);
response.statusCode = 200;
// 设置默认的首页
const requestPath = path === "/" ? "/index.html" : path;
// 检查.的索引
const index = requestPath.lastIndexOf(".");
// 裁切得到.后面的路径, 即文件类型
const suffix = requestPath.substring(index);
// 使用hash哈希表的数据结构,映射得到文件类型
const filesType = {
".html": "tex/html",
".css": "text/css",
".js": "text/javascript",
".png": "image/png",
".jpg": "image/jpeg"
};
// 设置响应头的文件类型
response.setHeader(
"Content-Type",
`${filesType[suffix]} || 'text/html'; charset=utf-8`
);
let content;
try {
content = fs.readFileSync(`./public${requestPath}`);
} catch (error) {
content = "该文本不存在";
response.statusCode = 404;
}
response.write(content);
response.end();
动态服务器
定义
动态网页是相对于静态网页而言的。当浏览器请求服务器的某个页面时,服务器根据当前时间、环境参数、数据库操作等动态的生成HTML页面,然后在发送给浏览器(后面的处理就跟静态网页一样了)。很明显,动态网页中的“动态”是指服务器端页面的动态生成,相反,“静态”则指页面是实实在在的、独立的文件。
原理
静态VS动态
- 对于一个业务稳定,页面变化频率不大的公司来说,静态网站是一个很好的选择
- 对于一个公司规模比较大的公司来说,经常会有动态信息要发布给浏览者,使用动态网站的后台来管理网站信息。
Cookie
定义
Cookie是服务器发给浏览器的一段字符串,浏览器必须保存这个Cookie,除非用户删除。之后,用户发起任何二级域名请求,浏览器必须附上Cookie。
例如: 电影院检票员,根据电影票来决定用户是否能进入电影院。Cookie就是电影票,有Cookie就是登录了,没有Cookie就是没有登录。
Session
定义
由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session
例如: 比如购物车,当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,并且跟踪用户,这样才知道购物车里面有几本书
原理: 把用户信息放在服务的X里,再给信息一个随机id,把随机id发给浏览器,后端下次读取id时,通过x[id]获取用户信息。因为id很长,而且随机,所以用户无法篡改id。这里的X是文件,不能用内存,因为断电内存就清空了,这个X就是session
实例代码2
目标0: 以json文件搭建数据库
结构:
[
{id:1, name: "tab", password: "aaaa", age: "1"},
{id:1, name: "frank", password: "bbbb", age: "2"}
]
读取数据
// 服务器读取数据文件,转化为字符串
const string = fs.readFileSync('./database/users.json').toString()
// 把json类型的字符串转为为JS类型的数组,即反序列化
const userArray = JSON.parse(string)
存储数据
// 新建数据,push到JS类型的数组里
const userQ = { id: 4, name: "tony", password: "tttt" };
array.push(userQ);
// 使用JSON.stringify转化为json类型的字符串,即序列化
const string = JSON.stringify(array);
// 服务区读写数据文件,存储新的信息
fs.writeFileSync("./database/user.json", string);
目标1:实现用户注册功能
前端写form,监听事件,发送POST请求
<body>
<form id="registerForm">
<div>
<label>用户名 <input type="text" name="name"/></label>
</div>
<div>
<label>密码 <input type="password" name="password"/></label>
</div>
<div>
<button type="submit">提交</button>
</div>
</form>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
const $form = $("#registerForm");
$form.on("submit", e => {
e.preventDefault();
const name = $form.find("input[name=name]").val();
const password = $form.find("input[name=password]").val();
$.ajax({
method: "POST",
url: "/register",
contentType: "text/json;charset=UTF-8",
data: JSON.stringify({ name, password })
}).then(
() => {
alert("恭喜你,注册成功");
location.href = "/login.html";
},
() => {}
);
});
</script>
</body>
后端接受POST请求,读取请求体中的name和password,写入数据库
if (path === "/register" && method === "POST") {
response.setHeader("Content-Type", "text/html;charset=UTF-8");
const usersArray = JSON.parse(fs.readFileSync("./database/user.json"));
const array = [];
// 分段监听数据上传事件,push到空数组
request.on("data", chunk => {
array.push(chunk);
});
// 如果请求的数据上传结束,打印出数据并给出响应
request.on("end", () => {
const string = Buffer.concat(array).toString();
const obj = JSON.parse(string);
console.log(obj.name);
console.log(obj.password);
const lastUser = usersArray[usersArray.length - 1];
const newUser = {
// id 为最后一个用户的id +1
id: lastUser ? lastUser.id + 1 : 1,
name: obj.name,
name: obj.password
};
usersArray.push(newUser);
fs.writeFileSync("./database/user.json", JSON.stringify(usersArray));
response.end();
});
}
目标2:实现用户登录功能
新增sign.html网页,用户用来提交用户名和密码,然后跳转到新增home.html网页。前端写form,监听事件,发送POST请求
<body>
<h1>登录页面</h1>
<form id="logInForm">
<div>
<label>用户名 <input type="text" name="name"/></label>
</div>
<div>
<label>密码 <input type="password" name="password"/></label>
</div>
<div>
<button type="submit">登录</button>
</div>
</form>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
const $form = $("#logInForm");
$form.on("submit", e => {
e.preventDefault();
const name = $form.find("input[name=name]").val();
const password = $form.find("input[name=password]").val();
$.ajax({
method: "POST",
url: "/login",
contentType: "text/json;charset=UTF-8",
data: JSON.stringify({ name, password })
}).then(
() => {
alert("登录成功");
location.href = "/home.html";
},
() => {}
);
});
</script>
</body>
后端接受POST请求,读取请求体中的name和password, 遍历数据库数据进行匹配, 得出结果
if (path === "/login" && method === "POST") {
response.setHeader("Content-Type", "text/html;charset=UTF-8");
const usersArray = JSON.parse(fs.readFileSync("./database/user.json"));
const array = [];
// 分段监听数据上传事件,push到空数组
request.on("data", chunk => {
array.push(chunk);
});
// 如果请求的数据上传结束,打印出数据并给出响应
request.on("end", () => {
const string = Buffer.concat(array).toString();
const obj = JSON.parse(string);
const checkResult = usersArray.find(
user => user.name === obj.name && user.password === obj.password
);
if (checkResult === undefined) {
response.statusCode = 400;
response.setHeader("Content-Type", "text/json;charset=UTF-8");
response.end(`{"errorCode": 4001}`);
} else {
response.statusCode = 200;
response.end();
}
});
} else if (path === "/home.html") {
response.end("home");
}
目标3:标记用户已登录,显示用户名
设置Cookie, home.html渲染前获取user 信息,有则显示用户名,没有则提示登录。
if (path === "/login" && method === "POST") {
response.setHeader("Content-Type", "text/html;charset=UTF-8");
const usersArray = JSON.parse(fs.readFileSync("./database/user.json"));
const array = [];
// 分段监听数据上传事件,push到空数组
request.on("data", chunk => {
array.push(chunk);
});
// 如果请求的数据上传结束,打印出数据并给出响应
request.on("end", () => {
const string = Buffer.concat(array).toString();
const obj = JSON.parse(string);
const checkResult = usersArray.find(
user => user.name === obj.name && user.password === obj.password
);
if (checkResult === undefined) {
response.statusCode = 400;
response.setHeader("Content-Type", "text/json;charset=UTF-8");
response.end(`{"errorCode": 4001}`);
} else {
response.statusCode = 200;
response.setHeader("Set-Cookie", `user_id=${checkResult.id}; HttpOnly`);
response.end();
}
});
} else if (path === "/home.html") {
const cookie = request.headers["cookie"];
console.log(cookie);
let userId;
try {
userId = cookie
.split(";")
.filter(s => s.indexOf("user_id=") >= 0)[0]
.split("=")[1];
} catch (error) {}
console.log(userId);
if (userId) {
const usersArray = JSON.parse(fs.readFileSync("./database/user.json"));
const user = usersArray.find(user => user.id.toString() === userId);
const homeHtml = fs.readFileSync("./public/home.html").toString();
let string;
if (user) {
string = homeHtml
.replace("{{loginStatus}}", "已登录")
.replace("{{user.name}}", user.name);
} else {
string = homeHtml
.replace("{{loginStatus}}", "未登录")
.replace("{{user.name}}", "");
}
response.write(string);
} else {
const homeHtml = fs.readFileSync("./public/home.html").toString();
const string = homeHtml
.replace("{{loginStatus}}", "未登录")
.replace("{{user.name}}", "");
response.write(string);
}
response.end();
目标4:防止篡改userId
目标3的代码有一个BUG,用户可以通过开发者工具或者JS篡改useId
思路一是加密,将userId加密后发送给前端,后端读取返回的useId时解密, 使用Json Web Token。思路二是把信息隐藏在服务器中, 使用session
const session = JSON.parse(fs.readFileSync("./session.json").toString());
console.log("有个傻子发请求过来啦!路径(带查询参数)为:" + pathWithQuery);
if (path === "/login" && method === "POST") {
response.setHeader("Content-Type", "text/html;charset=UTF-8");
const usersArray = JSON.parse(fs.readFileSync("./database/user.json"));
const array = [];
// 分段监听数据上传事件,push到空数组
request.on("data", chunk => {
array.push(chunk);
});
// 如果请求的数据上传结束,打印出数据并给出响应
request.on("end", () => {
const string = Buffer.concat(array).toString();
const obj = JSON.parse(string);
const checkResult = usersArray.find(
user => user.name === obj.name && user.password === obj.password
);
if (checkResult === undefined) {
response.statusCode = 400;
response.setHeader("Content-Type", "text/json;charset=UTF-8");
response.end(`{"errorCode": 4001}`);
} else {
response.statusCode = 200;
const random = Math.random();
session[random] = { user_id: checkResult.id };
console.log(session[random]);
console.log(session);
fs.writeFileSync("./session.json", JSON.stringify(session));
response.setHeader("Set-Cookie", `session_id=${random}; HttpOnly`);
}
response.end();
});
} else if (path === "/home.html") {
const cookie = request.headers["cookie"];
let sessionId;
try {
sessionId = cookie
.split(";")
.filter(s => s.indexOf("session_id=") >= 0)[0]
.split("=")[1];
} catch (error) {}
console.log(sessionId);
if (sessionId && session[sessionId]) {
const userId = session[sessionId].user_id;
console.log(`useId:${userId}`);
const usersArray = JSON.parse(fs.readFileSync("./database/user.json"));
const user = usersArray.find(user => user.id === userId);
const homeHtml = fs.readFileSync("./public/home.html").toString();
let string = "";
if (user) {
string = homeHtml
.replace("{{loginStatus}}", "已登录")
.replace("{{user.name}}", user.name);
}
response.write(string);
} else {
const homeHtml = fs.readFileSync("./public/home.html").toString();
const string = homeHtml
.replace("{{loginStatus}}", "未登录")
.replace("{{user.name}}", "");
response.write(string);
}
response.end();
}