nodejs- 实现动态WEB服务器

136 阅读6分钟

在node中使用art-template

npm install art-template
  • 核心方法
// 基于模板路径渲染模板
//参数1:文件的路径
//参数2:数据
//返回值:返回渲染后的内容
// template(filename, data)
let html = template(path.join(__dirname, "pages", "index.html"), {name:"大吉大利,今晚吃鸡"});

注意点:文件的路径必须是绝对路径

get请求处理-url模块

  • 说明:用于 URL 处理与解析
  • 注意:通过url拿到的查询参数都是字符串格式
// 导入url模块
var url = require('url')

// 解析 URL 字符串并返回一个 URL 对象
// 第一个参数:表示要解析的URL字符串
// 第二个参数:是否将query属性(查询参数)解析为一个对象,如果为:true,则query是一个对象
var ret = url.parse('http://localhost:3000/details?id=1&name=jack', true)
console.log(ret.query) // { id: '1', name: 'jack' }

服务端重定向

res.writeHead(302, {
  'Location': '/'
})
res.end()

POST请求参数的处理

  • 说明:POST请求可以发送大量数据,没有大小限制
// 接受POST参数
var postData = []

// data事件:用来接受客户端发送过来的POST请求数据
var result = "";
req.on('data', function (chunk) {
  result += chunk;
})

// end事件:当POST数据接收完毕时,触发
req.on('end', function () {
  cosnole.log(result); 
})

请求体处理-querystring模块

  • 用于解析与格式化 URL 查询字符串
  • 注意:只在专门处理查询字符串时使用
// foo=bar&abc=xyz&abc=123
var querystring = require('querystring')

// 将查询参数转化为对象
// 第一个参数: 要解析的 URL 查询字符串
querystring.parse('foo=bar&abc=xyz') // { foo: 'bar', abc: 'xyz' }

服务器搭建完整代码

// 1- 搭建服务器
// 引入http 
const http = require('http');

// 创建服务器 
const server = http.createServer();
const fs = require('fs');
const path = require('path');
const template = require('art-template');
const mime = require('mime');
const url = require('url');
const moment = require('moment');
const queryString = require('querystring');

// data.json文件绝对路径 
let dataPath = path.join(__dirname, 'data/data.json');

// 监听请求 
server.on('request', (req, res) => {
  console.log('req.url:', req.url);
  console.log('req.method:', req.method);
  // 路由: 根据不同的请求 返回不同的响应 
  if (req.url.startsWith('/index') || req.url == '/') {  // 首页
    // 1- 去读取数据库(data.json)中的数据
    // 2- 使用模板引擎 渲染 读取的数据 
    // 3- 将服务器渲染好页面,发送给浏览器,进行解析

    // 1- 去读取数据库(data.json)中的数据
    fs.readFile(dataPath, 'utf8', (err, data) => {
      if (err) {
        return console.log(err);
      }
      //读取了数据库的数据 , 把json字符串 转成js数据 
      data = JSON.parse(data);
      console.log(data); // 对象
      // 对数据进行排序 
      // data.list.sort(function (a, b) { return b.id - a.id })
      data.list.sort((a, b) => b.id - a.id);
      // 使用模板渲染  art-template 
      let str = template(path.join(__dirname, 'pages/index.html'), data);
      // 把渲染好页面返回给浏览器解析 
      res.end(str);
    })
  } else if (req.url.startsWith('/add')) {  // 添加
    //直接读取add 页面返回  
    fs.readFile(path.join(__dirname, 'pages/add.html'), (err, data) => {
      if (err) {
        return console.log(err);
      }
      //返回add页面给浏览器 
      res.end(data);
    })
  } else if (req.url.startsWith('/assets')) { // 静态资源 
    // 直接返回前端所需的静态资源即可
    fs.readFile(path.join(__dirname, req.url), (err, data) => {
      if (err) {
        return console.log(err);
      }
      // 给资源设置mime类型 
      res.setHeader('content-type', mime.getType(req.url));
      //返回静态资源给浏览器 
      res.end(data);
    })
  } else if (req.url.startsWith('/delete')) { // 删除
    // 1- 获取前端传递id 
    // 2- 根据id 去后台删除对应数据
    //    数据 以字符串的形式永久存储, 以js数据 方式进行操作 
    //    1- 先读取data.json数据 , 转成js对象
    //    2- 从对象中进行删除 
    //    3- 删除完成后, 把对象转成json字符串,写回到json文件中 
    // 3- 页面重新渲染,看到删除结果 
    // /delete?id=1560352105444

    // 1- 获取前端传递id 
    let id = url.parse(req.url, true).query.id;
    // 2- 根据id 去后台删除对应数据
    // 2-1- 先读取data.json数据 , 转成js对象
    fs.readFile(dataPath, 'utf8', (err, data) => {
      if (err) {
        return console.log(err);
      }
      // 读取成功 , 把json转成字符串
      data = JSON.parse(data);
      console.log('data:', data);
      // 数组是根据下标进行删除的  arr.splice(从哪删, 删几个, 替换项)
      // 根据id找下标 
      // let index = data.list.findIndex(function (v) {
      //   return v.id == id; 
      // })
      let index = data.list.findIndex(v => v.id == id);
      console.log(index);
      // 根据下标去删除
      data.list.splice(index, 1);
      // 3- 删除完成后, 把对象转成json字符串,写回到json文件中 
      data = JSON.stringify(data);
      fs.writeFile(dataPath, data, (err) => {
        if (err) {
          return console.log(err);
        }
        //写入成功了, 跳转到首页,看到删除结果 
        // 我们在服务器,服务器无法直接控制浏览器跳转, 但是服务器可以通过响应报文, 通知浏览器跳转, 
        // 在响应头中进行设置 
        res.statusCode = 302; // 设置状态  
        res.setHeader('location', '/'); //跳转地址
        res.end(); //终止请求        
      })
    })

  } else if (req.url.startsWith('/submit') && req.method == 'GET') { // get 添加
    // 1- 后台获取前端提交表单数据 
    // 2- 把数据添加到数据库中 data.json中 
    //    数据 以字符串的形式永久存储, 以js数据 方式进行操作 
    //     1- 先读取data.json数据 , 转成js对象
    //     2- 向对象的数组中进行添加 
    //     3- 添加完成后, 把对象转成json字符串,写回到json文件中 
    // 3- 添加完成后,跳转到首页, 看到添加的效果 


    // 1- 后台获取前端提交表单数据
    let info = url.parse(req.url, true).query;

    // 2- 给info 添加  id(时间戳) 和创建时间 
    info.id = Date.now();
    info.created = moment().format('YYYY年MM月DD日 HH:mm:ss');

    console.log(info);
    // 3-把数据添加到数据库中 data.json中 
    // 1- 先读取data.json数据 , 转成js对象
    fs.readFile(dataPath, 'utf8', (err, data) => {
      if (err) {
        return console.log(err);
      }
      data = JSON.parse(data); // json字符串 --> js 对象 
      console.log(data);
      // 2- 向对象的数组中进行添加 
      data.list.push(info);
      // 3- 添加完成后, 把对象转成json字符串,写回到json文件中 
      data = JSON.stringify(data);
      fs.writeFile(dataPath, data, (err) => {
        if (err) {
          return console.log(err);
        }
        //写入成功 , 跳转首页 
        res.statusCode = 302; // 设置状态码 
        res.setHeader('location', '/'); // 设置跳转地址 
        res.end(); // 终止响应 
      });
    })



  } else if (req.url.startsWith('/submit') && req.method == 'POST') { // post 添加
    //   前端:
    //   浏览器会先将文件分割成片段, 依次传递给后台 , [少量多次]
    // 后台:
    //   后台需要持续接收前端传递的数据片段, 进行拼接 , 当前所有的片段都传递完成后,才能正式使用这个数据;     

    //   后台如何持续接收前端传递 数据: 用事件监听即可; 
    //   服务器怎么知道数据全部传完了, 服务器收到浏览器结束的标志,也会触发事件, 就知道数据传完了 

    let str = ''; // 拼接传递的数据
    let num = 0;
    // 服务器 接收的前端post方式传递的数据  触发data
    req.on('data', (chunk) => { // chunk 块,片段 
      str += chunk;
      console.log(++num);
    })
    // 服务器接收到浏览器的post方式, 结束标志时会触发 
    req.on('end', function () {
      //使用数据    nickname=12&title=12&content=12     
      let info = queryString.parse(str);

      // 给 info 添加id 和创建时间  
      info.id = Date.now();
      info.created = moment().format('YYYY年MM月DD日 HH:mm:ss');
      console.log('info:', info);
      // 把数据添加到数据库
      // 1- 先读取data.json数据 , 转成js对象
      fs.readFile(dataPath, 'utf8', (err, data) => {
        if (err) {
          return console.log(err);
        }
        data = JSON.parse(data); // json --> js数据 
        // 2- 向对象的数组中进行添加 
        data.list.push(info);
        // 3- 添加完成后, 把对象转成json字符串,写回到json文件中 
        data = JSON.stringify(data); //js 对象  ---> json 
        fs.writeFile(dataPath, data, (err) => {
          if (err) {
            return console.log(err);
          }
          // 添加成功, 跳转到首页 
          res.statusCode = 302; //状态码
          res.setHeader('location', '/index'); // 设置跳转地址
          res.end(); //终止响应 
        })
      })


    })

  } else { // 404 
    res.end('404');
  }
});

// 启动服务器 
server.listen(9999, () => console.log('http://localhost:9999 服务器已启动'));