nodejs 3分钟学会系列教程(7) 封装静态web服务器 路由 EJS模版引擎 GET POST

137 阅读5分钟

1、先解决封装静态web 服务器

1)

  • 先将 web-server文件夹 复制一份命名 web-server-fengzhuang 进行封装
  • 将common.js 改成 routes.js 内容对应修改
const fs = require("fs");
const url = require("url");
const path = require("path");

// 私有方法

var getFileMine = function (extname) {
  var data = fs.readFileSync("./data/test.json"); // 同步方法
  var mimeObj = JSON.parse(data.toString());
  return mimeObj[extname];
};

//导出部分命名为 static
exports.static = function (req, res, staticPath) {
  // 1、读取地址
  // var pathname = req.url;
  var pathname = url.parse(req.url).pathname;
  // console.log(url.parse(req.url));
  // 需要加一点判断
  pathname = pathname == "/" ? "/test.html" : pathname;

  // 这个方法  可以获取后缀名 path.extname
  var extname = path.extname(pathname);
  // 2、通过fs 模块读取文件
  if (pathname != "/favicon.ico") {
    fs.readFile("./" + staticPath + pathname, (err, data) => {
      if (err) {
        res.writeHead(404, { "Content-Type": 'text/html;charset="utf-8"' });
        res.end("404 这个界面不存在");
      }
      var mine = getFileMine(extname);
      res.writeHead(200, { "Content-Type": "" + mine + ';charset="utf-8"' });
      res.end(data);
    });
  }
};

2) app-1.js 也需要 修改一下

var http = require("http");

// 引入 routes.js
const routes = require("./module/routes");

http
  .createServer(function (req, res) {
    // 创建 静态web服务器
    routes.static(req, res, "static");
  })
  .listen(3001);


3) node app-1.js 就可启动 服务 检查一下 对应 文件类型是正确的

2、路由

1)

  • 比如页面 http://127.0.0.1:3001/login 表示登陆 /register表示注册 /admin表示后台管理 2)routes.js 里先删除 404界面 因为需要继续向下匹配路由 并加上这一句
if(!err){
        var mine = getFileMine(extname);
      res.writeHead(200, { "Content-Type": "" + mine + ';charset="utf-8"' });
      res.end(data);
    }
  • app-1.js 里面开始 做判断和匹配操作
var http = require("http");
var url = require("url");
// 引入 routes.js
const routes = require("./module/routes");

http
  .createServer(function (req, res) {
    // 创建 静态web服务器
    routes.static(req, res, "static");

    // 路由
    var pathname = url.parse(req.url).pathname;

    if (pathname == "/login") {
      res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end("执行登陆");
    } else if (pathname == "/register") {
      res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end("执行注册");
    } else if (pathname == "/admin") {
      res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end("处理后的业务逻辑");
    } else {
      res.writeHead(404, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end("页面不存在");
    }
  })
  .listen(3001);

  • routes.js 里面
 // 2、通过fs 模块读取文件
  if (pathname != "/favicon.ico") {
    fs.readFile("./" + staticPath + pathname, (err, data) => {
      //   if (err) {
      //     res.writeHead(404, { "Content-Type": 'text/html;charset="utf-8"' });
      //     res.end("404 这个界面不存在");
      //   }
      if (!err) {
        var mine = getFileMine(extname);
        res.writeHead(200, { "Content-Type": "" + mine + ';charset="utf-8"' });
        res.end(data);
      }
    });
  }
  • 这时候 尝试 启动 node app-1.js 发现 可以 /login 不过 发生乱码
  • 还有 一个问题 http://127.0.0.1:3001 展示 不出来了 排查一下 发现 fs.readFile()是异步方法
  • 可以在这个地方改成 同步的fs.readFileSync()
  • 更改后是这样的
const fs = require("fs");
const url = require("url");
const path = require("path");

// 私有方法   不暴露出来 只在这个里面使用
var getFileMine = function (extname) {
  var data = fs.readFileSync("./data/test.json"); // 同步方法
  var mimeObj = JSON.parse(data.toString());
  return mimeObj[extname];
};

//导出部分命名为 static
exports.static = function (req, res, staticPath) {
  // 1、读取地址
  // var pathname = req.url;
  var pathname = url.parse(req.url).pathname;
  // console.log(url.parse(req.url));
  // 需要加一点判断
  pathname = pathname == "/" ? "/test.html" : pathname;

  // 这个方法  可以获取后缀名 path.extname
  var extname = path.extname(pathname);
  // 2、通过fs 模块读取文件
  if (pathname != "/favicon.ico") {
    try {
      var data = fs.readFileSync("./" + staticPath + pathname);
      if (data) {
        var mine = getFileMine(extname);
        res.writeHead(200, { "Content-Type": "" + mine + ';charset="utf-8"' });
        res.end(data);
      }
    } catch (error) {}
  }
};

  • 重启 node app-1.js 发现 基本正常 不过 三个路由还是乱码状态 继续尝试解决
  • 后面这种 东西 不要手动敲哈 偷偷把上面 也改了 应该没人知道
if (pathname == "/login") {
      res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end("执行登陆");
  • 重启 后发现 问题 解决啦 nice

3、 EJS模版引擎

1) 将 web-server-fengzhaung 复制一份 然后 命名为 web-ejs

2) 在npmjs.com 搜索 ejs 然后 在 web-ejs 安装这个模块 npm install ejs

3)该文件夹下面 新建 views 写一个 文件 login.ejs 内容是 ejs 模版引擎

4) app-1.js 里面 增加一点内容

var ejs = require("ejs");
// if 判断里面 加上 这部分内容
if (pathname == "/login") {

      var msg = "数据库里面获取的数据";
      ejs.renderFile("./views/login.ejs", { msg: msg }, (err, data) => {
        res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
        res.end(data);
      });
      ......
}

5) 执行 一下 node app-1.js 启动后

6) 可直接 将 数据库数据 展示 在页面上

  • 这样做的好处是 数据库改变数据 网页随之刷新 就行
  • 这个语法 有很多 可以直接 在ejs 上看

7) 接下来 我们再 模拟一个 在数据库拿到的数组 在页面渲染出来

  • login.ejs 里面 这样写
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>这是一个登陆页面</h2>

    <h3><%=msg%></h3>

    <ul>
        <%for(var i=0;i < tlist.length; i ++){%>
        <li><%=tlist[i].title%></li>
        <%}%>
    </ul>
</body>

</html>
  • app-1.js 里面这样写
if (pathname == "/login") {
      var msg = "数据库里面获取的数据";
      var list = [
        { title: "test111" },
        { title: "test222" },
        { title: "test333" },
        { title: "test444" },
      ];
      ejs.renderFile(
        "./views/login.ejs",
        { msg: msg, tlist: list },
        (err, data) => {
          res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
          res.end(data);
        }
      );
      ......
      }
  • 然后 node app-1.js 启动服务

  • 后续 使用 需要继续 看 文档 先 学到这里

  • 注意到一个规律 数据部分 写在 <%写在这个中间的位置%>

4、Get 请求

1)

2)回顾一下 我们 如何获取 地址后面的 get 传值呢 这部分 news?page=2&id=1 ?

比如现在有个网址是 http://127.0.0.1:3001/news?page=2&id=1

  • nice 有了 这部分 基础 一切貌似 就简单了起来
  • 我们 尝试继续完善一下 这部分功能

3)那么 我们在 app-1.js 稍微 改动一下

if (pathname == "/news") {
      // 获取 get 传值
      var query = url.parse(req.url).query;
      console.log(query);

      res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end(query);
      .........
      }

  • 重启 node app-1.js 然后写入 http://127.0.0.1:3001/news?page=2&id=1

  • 就可看到数据

  • 不过当前打印出来的是 字符串 如何转化成对象呢 ?

  • node app-1.js

  • 控制台可以看到 结果

  • 那么 我们 怎么看数据类型呢 ? 怎么确定是 get 请求呢 ?

5、 Post请求

1)我们 在 app-1.js 稍微 改动一部分 内容 看看post 的过程

2)在 views 文件夹 下面 新建 form.ejs 文件 里面写点内容

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <form action="/doRegister" method="post">
        用户名:<input type="text" name="username">
        <br>
        <br>
        密码: <input type="password" name="password">
        <br>
        <br>
        <input type="submit" value="提交">

    </form>
</body>

</html>

  • app-1.js 里面 稍微改动一点
else if (pathname == "/register") {
      //post 操作
      ejs.renderFile("./views/form.ejs", {}, (err, data) => {
        res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
        res.end(data);
      });
  • node app-1.js 可看到

3) 下面一个 问题 post 值怎么传递呢 ?

  • 需要 再做一个页面 获取 post传值
else if (pathname == "/doRegister") {
      res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      res.end("post ok");

4)原生 node js 获取 post 的值

 } else if (pathname == "/doRegister") {
      // res.writeHead(200, { "Content-Type": ' text/html ;charset="utf-8"' });
      // res.end("post ok");
      // 获取 post 传值
      var postData = "";
      req.on("data", (chunk) => {
        postData += chunk;  // 通过对片段的拼接得到
      });
      req.on("end", () => {
        console.log(postData);
        res.end(postData);   // 需要注意 这个地方是字符串形式可直接打印 对象形式不能直接打印出来
      });

  • node app-1.js