动态服务器(未完)

静态服务器 VS 静态服务器

也叫动态网页 VS 静态网页

判断依据

  • 没有请求数据库,就是静态服务器
  • 请求了数据库,就是动态服务器

这次直接用 JSON 文件当做数据库

引入 jQuery 的方法: (www.bootcdn.cn/jquery/)

image.png

新建目录 db (数据库缩写),在 db 下新建 users.json,数据库的结构就是数组,里面是哈希表

[
    {"id":1,"name":"wbs","password":"zzz"},
    {"id":2,"name":"tom","password":"aaa"}
]
复制代码

怎么读和写数据库呢?在根目录下新建 test.js

const fs = require("fs");

//读数据库
const usersString = fs.readFileSync("./db/users.json").toString();
const usersArray = JSON.parse(usersString); //把字符串变成对应的数组对象
console.log(usersArray);

//写数据库
const user3 = { id: 3, name: "kok", password: "bbb" };
usersArray.push(user3);
const string = JSON.stringify(usersArray);
fs.writeFileSync("./db/users.json", string);

复制代码

写入数后的 users.json

[
    {"id":1,"name":"wbs","password":"zzz"},
    {"id":2,"name":"tom","password":"aaa"},
    {"id":3,"name":"kok","password":"bbb"}
]
复制代码
  • JSON.stringify() //序列化
  • JSON.parse() //返序列化
  • type of 可以查看对象类型

目标 1 :实现用户注册功能

  • 用户提交用户名和密码
  • users.json 里就新增了一行数据

思路

  • 前端写一个 form,让用户填写 name和 password
  • 前端监听 submit 事件
  • 前端发送 post 请求,数据位于请求体
  • 后端接收 post 请求
  • 后端获取请求体中的 name 和 password
  • 后端存储数据

具体步骤

  1. 在 pubilc 目录下 新建 regist.html,写一个 form 表单
  2. 监听 submit 事件
  • 阻止form表单的默认事件
  • 获取用户数据:找到input的name为name的元素,获得用户输入的值,找到input的name为password的元素,获得用户输入的值
  1. 用 ajax 发送 POST 请求,把数据传给服务器
  • 请求的url是/register
  • 传给服务器的数据也就是请求体内容为刚刚获取的用户数据的json字符串
  • 请求体的类型也就是传给服务器的数据类型为json
  • 再用.then设置请求成功函数(跳转到登录页面(/sign_in.html))和失败后的函数(啥也不干)
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    //直接抄淘宝的 meta vp
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"
    />
    <title>注册</title>
  </head>
  <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.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
      const $form = $("#registerForm");
      $form.on("submit", (e) => {
        e.preventDefault(); //阻止 form 表单默认事件
        const name = $form.find("input[name=name]").val();  //找到相应的 name 和 password 的值
        const password = $form.find("input[name=password]").val();
        console.log(name, password);
        $.ajax({
          method: "POST",
          url: "/register",
          contentType: "text/json; charset=UTF-8", //让服务器知道我们上传的是 JSON 字符串
          data: JSON.stringify({ name, password }),
        }).then(
          () => {
            alert("注册成功");
            location.href = "https://juejin.cn/sign_in.html";
          },
          () => {}
        );
      });
    </script>
  </body>
</html>
复制代码

很显然, register 的请求会得到一个 404,因为 register 不对应任何一个文件,服务器如何获取到用户的 name 和 password 呢,那就需要在请求这个文件之前,看一下有没有 register ,server.js 代码如下

var http = require("http");
var fs = require("fs");
var url = require("url");
var port = process.argv[2];

if (!port) {
  console.log("请指定端口号好不啦?\nnode server.js 8888 这样不会吗?");
  process.exit(1);
}

var server = http.createServer(function (request, response) {
  var parsedUrl = url.parse(request.url, true);
  var pathWithQuery = request.url;
  var queryString = "";
  if (pathWithQuery.indexOf("?") >= 0) {
    queryString = pathWithQuery.substring(pathWithQuery.indexOf("?"));
  }
  var path = parsedUrl.pathname;
  var query = parsedUrl.query;
  var method = request.method;

  /******** 从这里开始看,上面不要看 ************/

  console.log("有个傻子发请求过来啦!路径(带查询参数)为:" + pathWithQuery);

  if (path === "/register" && method === "POST") {
    response.setHeader("Content-Type", "text/html;charset=utf-8");
    //读数据库
    const userArray = JSON.parse(fs.readFileSync("./db/users.json"));
    const array = [];
    //监听请求的上传事件,把chunk数据push到数组里,因为数据可能是一点一点上传,每上传一点,我就往数组里push一点数据
    request.on("data", (chunk) => {
      array.push(chunk);
    });
    //监听请求的结束事件,先把array里的数据变成字符串,这个字符串符合JSON语法,然后在把字符串变成js对象
    request.on("end", () => {
      const string = Buffer.concat(array).toString();
      const obj = JSON.parse(string);
      //写入数据库
      const lastUser = userArray[userArray.length - 1];
      const newUser = {
        //新用户
        // id 为如果最后一个用户存在 id就是最后一个用户的 id + 1,否则就是1
        id: lastUser ? lastUser.id + 1 : 1,
        name: obj.name,
        password: obj.password,
      };
      userArray.push(newUser);
      fs.writeFileSync("./db/users.json", JSON.stringify(userArray));
      response.end();
    });
  } else {
    response.statusCode = 200;
    // 默认首页
    const filePath = path === "/" ? "/index.html" : path;
    const index = filePath.lastIndexOf(".");
    // suffix 是后缀
    const suffix = filePath.substring(index);
    const fileTypes = {
      ".html": "text/html",
      ".css": "text/css",
      ".js": "text/javascript",
      ".png": "image/png",
      ".jpg": "image/jpeg",
    };
    response.setHeader(
      "Content-Type",
      `${fileTypes[suffix] || "text/html"};charset=utf-8`
    );
    let content;
    try {
      content = fs.readFileSync(`./public${filePath}`);
    } catch (error) {
      content = "文件不存在";
      response.statusCode = 404;
    }
    response.write(content);
    response.end();
  }

  /******** 代码结束,下面不要看 ************/
});

server.listen(port);
console.log(
  "监听 " +
    port +
    " 成功\n请用在空中转体720度然后用电饭煲打开 http://localhost:" +
    port
);

复制代码

目标 2:实现用户登录功能

  • 首页 home.html,已登录用户可看到自己用户名
  • 登录页 sign_in.html,供提交用户名和密码
  • 输入的用户名密码如果是匹配的,就自动跳转首页

sign_in.html 思路

  • 前端写一个 form,让用户填写name和password
  • 前端监听submit事件
  • 前端发送 post请求,数据位于请求体
  • 后端接收post请求
  • 后端获取请求体中的name和password
  • 后端读取数据,看是否有匹配的name和password
  • 如果匹配,后端应标记用户已登录,可是怎么标记?

新建登录页 sign_in.html,思路 register.html 相同

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover"
    />
    <title>登录</title>
  </head>
  <body>
    <form id="signInForm">
      <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.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
      const $form = $("#signInForm");
      $form.on("submit", (e) => {
        e.preventDefault(); //阻止 form 表单默认事件
        const name = $form.find("input[name=name]").val(); //找到相应的 name 和 password 的值
        const password = $form.find("input[name=password]").val();
        $.ajax({
          // ajax 发送 POST 请求
          method: "POST",
          url: "/sign_in",
          contentType: "text/json; charset=UTF-8", //让服务器知道我们上传的是 JSON 字符串
          data: JSON.stringify({ name, password }),
        }).then(
          () => {
            alert("登录成功");
            location.href = "https://juejin.cn/home.html";
          },
          () => {}
        );
      });
    </script>
  </body>
</html>
复制代码

在 server.js 写 sign_in 路由

  • 后端接收post请求
  • 后端获取请求体中的name和password
  • 后端读取数据,看是否有匹配的name和password
if (path === "/sign_in" && method === "POST") {
    response.setHeader("Content-Type", "text/html;charset=utf-8");
    //读数据库
    const userArray = JSON.parse(fs.readFileSync("./db/users.json"));
    const array = [];
    request.on("data", (chunk) => {
      array.push(chunk);
    });
    request.on("end", () => {
      const string = Buffer.concat(array).toString();
      const obj = JSON.parse(string);
      const user = userArray.find( //在数据库中找匹配的 name 和 password 
        (user) => user.name === obj.name && user.password === obj.password
      );
      if (user === undefined) { //没找到
        response.statusCode = 400;
        response.end(`{'errorCode': 4001}`);
      } else { //找到了
        response.statusCode = 200;
        response.end();
      }
    });
  }
复制代码

目标 3 :标记用户已登录 Cookie

Cookie 定义:

  • Cookie是服务器下发给浏览器的一段字符串
  • 浏览器必须保存这个Cookie(除非用户删除)
  • 之后发起相同二级域名请求(任何请求)时,浏览器必须附上Cookie

以公园门票作为对比(画图)

  • 假如你是公园检票员,你怎么知道谁能进谁不能进?
  • 有票能进,没票不能进
  • Cookie就是门票
  • 有Cookie就是登录了,没Cookie就没登录
  • 那后端给浏览器下发一个Cookie不就完事了嘛

Cookie 具体语法看 mdn

开发者工具 Application => Cookie 可以查看

在 public 目录下新建 home.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>首页</title>
  </head>
  <body>
    <p>{{loginStatus}}</p>
    <a href="https://juejin.cn/post/sign_in.html">登录</a>
  </body>
</html>
复制代码

建议只在后端设置 Cookie ,永远不要在前端设置 Cookie

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享