nodejs-3

创建静态服务器

web服务器一般是指网站服务器,可以向浏览器等web客户端提供文档,也可以防止网站文件让所有人浏览,还可以放置数据文件,让所有人下载。目前最主流的web服务器有:apache,nginx,IIS等

nodejs创建web服务器

这块在请求文件时会有一个文件名后缀转换的问题,通常请求的文件会有 .html .css .json .jpg .png 等格式的,可以在外面封装一个转换后缀名的方法直接调用,但是像 .json 这种格式的文件会有些不同,比如下面图片里说的,这时需要用到 url.prase() 来进行文件后缀名的获取。

  • app.js
const http = require('http');
const fs = require('fs');
const path = require('path');
// 这块的这个主要是为了解决.json格式的文件后缀名转换的问题
const url = require('url');
const common = require('./module/common')

http.createServer(function (req, res) {
  // 请求地址的样式 -> http://127.0.0.1:3000/index.html

  // 1 获取地址
  // let pathname = req.url;
  let pathname = url.parse(req.url).pathname;
  pathname = pathname === '/' ? '/index.html' : pathname;

  // path.extname() 可以获取后缀名
  let extname = path.extname(pathname);

  // 2 通过fs模块读取文件
  if (pathname !== '/favicon.ico') {
    fs.readFile('./static' + pathname, (err, data) => {
      if (err) {
        res.writeHead(404, { 'Content-Type': "text/html;charset='utf-8'" });
        res.end("404! 这个页面不存在");
      }

      let mime = common(extname);
      res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' });
      res.end(data);
    })
  }
}).listen(3000);

console.log('Server running at http://127.0.0.1:3000/');
  • common.js
  // 3 获取请求文件的后缀名
  /**
   * 请求的后缀名是.html的话,响应头就是 text/html
   * 请求的后缀名是.css的话,响应头就是 text/css
   * 请求的后缀名是.js的话,响应头就是 text/javascript
   */
 exports.getMime = function (extname) {
  switch (extname) {
    case '.html':
      return 'text/html';
    case '.css':
      return 'text/css';
    case '.js':
      return 'text/javascript';
    default:
      return 'text/html';
  }
}

通过从json文件中读取出来的文件后缀名

  • app.js
const http = require('http');
const fs = require('fs');
const path = require('path');
// 这块的这个主要是为了解决.json格式的文件后缀名转换的问题
const url = require('url');
const common = require('./module/common');

http.createServer(function (req, res) {
  // 请求地址的样式 -> http://127.0.0.1:3000/index.html

  // 1 获取地址
  // let pathname = req.url;
  let pathname = url.parse(req.url).pathname;
  pathname = pathname === '/' ? '/index.html' : pathname;

  // path.extname() 可以获取后缀名
  let extname = path.extname(pathname);

  // 2 通过fs模块读取文件
  // if (pathname !== '/favicon.ico') {
  //   fs.readFile('./static' + pathname, async (err, data) => {
  //     if (err) {
  //       res.writeHead(404, { 'Content-Type': "text/html;charset='utf-8'" });
  //       res.end("404! 这个页面不存在");
  //     }
  //     // 1 方法一 common.getFileMime()这个方法是个异步方法,所以需要用await获取
  //     let mime = await common.getFileMime(extname);
  //     res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' });
  //     res.end(data);
  //   })
  // }

  // 除了上面的async/await之外,还有另外一种可以获取到 common.getFileMime 异步方法里面的数据
  if (pathname !== '/favicon.ico') {
    fs.readFile('./static' + pathname, (err, data) => {
      if (err) {
        res.writeHead(404, { 'Content-Type': "text/html;charset='utf-8'" });
        res.end("404! 这个页面不存在");
      }
      let mime =  common.getFileMime(extname);
      res.writeHead(200, { 'Content-Type': ''+mime+';charset="utf-8"' });
      res.end(data);
    })
  }
}).listen(3000);

console.log('Server running at http://127.0.0.1:3000/');
  • common.js
  // 3 获取请求文件的后缀名
  /**
   * 请求的后缀名是.html的话,响应头就是 text/html
   * 请求的后缀名是.css的话,响应头就是 text/css
   * 请求的后缀名是.js的话,响应头就是 text/javascript
   */

  const fs = require('fs');

  // 这块的这个是后缀名是直接写死的,也就只有固定的几个
  // exports.getMime = function (extname) {
  //   switch (extname) {
  //     case '.html':
  //       return 'text/html';
  //     case '.css':
  //       return 'text/css';
  //     case '.js':
  //       return 'text/javascript';
  //     default:
  //       return 'text/html';
  //   }
  // }

  // 这块是从json文件中读取出来的文件后缀名
  // exports.getFileMime = function (extname) {
  //   return new Promise((resolve, reject) => {
  //     fs.readFile('./../data/mime.json', (err, json) => {
  //       if (err) {
  //         reject(err);
  //         return;
  //       }

  //       let mimeObj = JSON.parse(data.toString());
  //       // 上面这块是异步方法,不能直接返回,可以放在promise中
  //       resolve(mimeObj[extname])
  //     })
  //   })
  // }


  // 还有下面这种方法和上面的这个效果一样

  exports.getFileMime = function (extname) {
    // 下面这个是同步方法,如果nodejs中提供了这个方法的话就可以用了
    var data = fs.readFileSync('./data/mime.json');   // 同步方法读取内容(读取完后才会向下执行)
    let mimeObj = JSON.parse(data.toString());
    return mimeObj[extname];
  }
  • data/mime.json
{
  ".html":"text/html",
  ".css":"text/css",
  ".js":"text/javascript",
  ".zip":"application/zip",
  ".json":"application/json"
}

这样的话也是可以的

主要思路:
在浏览器中访问某个url的时候,如:http://127.0.0.1:3000/index.html

  • 先获取到浏览器中输入这个地址
  • 获取到地址之后,通过fs模块读取文件readFile这个方法,去static目录里面去读取一下访问的文件
  • 读取到文件之后就可以返回读取到的内容了,返回的时候要注意一下类型(就是通过mime来找对应的类型)

对静态web服务进行封装

将之前module/common.js改为module/routes.js

  • module/routes.js
const fs = require('fs');
const path = require('path');
const url = require('url');

let getFileMime = function (extname) {
  var data = fs.readFileSync('./data/mime.json'); // 同步方法读取内容(读取完后才会向下执行)
  let mimeObj = JSON.parse(data.toString());
  return mimeObj[extname];
}

exports.static = function (req, res, staticPath) {
  // 1 获取地址
  let pathname = url.parse(req.url).pathname;
  pathname = pathname === '/' ? '/index.html' : pathname;
  // path.extname() 可以获取后缀名
  let extname = path.extname(pathname);

  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! 这个页面不存在");
      }
      let mime = getFileMime(extname);
      res.writeHead(200, {
        'Content-Type': '' + mime + ';charset="utf-8"'
      });
      res.end(data);
    })
  }
}
  • app.js
const http = require('http');
const routes = require('./module/routes');

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

console.log('Server running at http://127.0.0.1:3000/');

这样封装后照样可以访问

路由

针对不同的请求URL,处理不同的业务逻辑

  • routes.js
const fs = require('fs');
const path = require('path');
const url = require('url');

let getFileMime = function (extname) {
  var data = fs.readFileSync('./data/mime.json'); // 同步方法读取内容(读取完后才会向下执行)
  let mimeObj = JSON.parse(data.toString());
  return mimeObj[extname];
}

exports.static = function (req, res, staticPath) {
  // 1 获取地址
  let pathname = url.parse(req.url).pathname;
  pathname = pathname === '/' ? '/index.html' : pathname;
  // path.extname() 可以获取后缀名
  let extname = path.extname(pathname);

  if (pathname !== '/favicon.ico') {
    try {
      let data = fs.readFileSync('./' + staticPath + pathname);
      if (data) {
        // 如果不是err的话,说明static目录中有需要的文件,有的话就读取出来
        // 没有的话就不做任何操作
        let mime = getFileMime(extname);
        res.writeHead(200, {
          'Content-Type': '' + mime + ';charset="utf-8"'
        });
        res.end(data);
      }
    } catch (error) {
      console.log(error);
    }
  }
}
  • app.js
const http = require('http');
const routes = require('./module/routes');
const url = require('url');

http.createServer(function (req, res) {
  // 创建静态web服务
  // 先走这里,如果能匹配的到的话,就会直接调用routes里面的那个res.end(data),不会继续向下匹配了
  routes.static(req, res, 'static');

  // 路由
  let pathname = url.parse(req.url).pathname;
  // 配合路由的话,当你加载不到一个页面的时候你需要继续向下匹配,看下面的路由能不能匹配到,如果不行的话可以返回404
  if(pathname === '/login'){
    res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
    res.end("login");
  }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(3000);

console.log('Server running at http://127.0.0.1:3000/');

ejs

  • install
npm install ejs
  • ejs 的用法
ejs.renderFile(filename, data, options,  (err, data) => {
  // str => rendered html string
})
  • views/login.ejs
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <h2>这是一个哈哈哈</h2>
  <h3><%=msg%></h3>
  <ul>
    <%for(var i = 0; i < list.length; i++){%>
    <li>
      <%=list[i].name%>
    </li>
    <%}%>
  </ul>
</body>

</html>
  • app.js
const http = require('http');
const routes = require('./module/routes');
const url = require('url');
const ejs = require('ejs');

http.createServer(function (req, res) {
  // 创建静态web服务
  // 先走这里,如果能匹配的到的话,就会直接调用routes里面的那个res.end(data),不会继续向下匹配了
  routes.static(req, res, 'static');

  // 路由
  let pathname = url.parse(req.url).pathname;
  // 配合路由的话,当你加载不到一个页面的时候你需要继续向下匹配,看下面的路由能不能匹配到,如果不行的话可以返回404
  if (pathname === '/login') {
    let msg = 'database data';
    let list = [{
        name: '111'
      },
      {
        name: '222'
      },
      {
        name: '333'
      }
    ]
    // 这块加载的文件是动态的,和在static中写的是不一样的
    ejs.renderFile('./views/login.ejs', {
      msg: msg,
      list: list
    }, (err, data) => {
      res.writeHead(200, {
        'Content-Type': 'text/html;charset="utf-8"'
      });
      res.end(data);
    })

  } 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(3000);

console.log('Server running at http://127.0.0.1:3000/');

get / post

  • views/form.js
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <form action="/doLogin" method="post">
    用户名:<input type="text" name="username" />
    密 码:<input type="text" name="password" />
    <input type="submit" value="提交">
  </form>
</body>
</html>
  • app.js
const http = require('http');
const routes = require('./module/routes');
const url = require('url');
const ejs = require('ejs');

http.createServer(function (req, res) {
  // 创建静态web服务
  // 先走这里,如果能匹配的到的话,就会直接调用routes里面的那个res.end(data),不会继续向下匹配了
  // routes.static(req, res, 'static');

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

  // 获取请求类型
  console.log(req.method);
  // 配合路由的话,当你加载不到一个页面的时候你需要继续向下匹配,看下面的路由能不能匹配到,如果不行的话可以返回404
  if (pathname === '/news') {
    // get请求演示
    var query = url.parse(req.url, true).query;
    console.log(query);
    res.writeHead(200, {
      'Content-Type': 'text/html;charset="utf-8"'
    });
    res.end("get传值获取成功");
  } else if (pathname === '/login') {
    // post请求演示
    ejs.renderFile("./views/form.ejs", {}, (err, data) => {
      res.writeHead(200, {
        'Content-Type': 'text/html;charset="utf-8"'
      });
      res.end(data);
    })
  } else if (pathname === '/doLogin') {
    // 获取post传值

    let postData = '';
    req.on('data', (chunk)=>{
      postData += chunk;
    })

    req.on('end', ()=>{
      console.log(postData);
      res.end(postData);
    })

  } else {
    res.writeHead(404, {
      'Content-Type': 'text/html;charset="utf-8"'
    });
    res.end("页面不存在");
  }
}).listen(3000);

console.log('Server running at http://127.0.0.1:3000/');

这块demo练习的就是一个简单的登录页面,获取这个登录页面是get请求,在登录页面输入对应的username和password之后点击提交是post请求,点击完提交之后获取到输入的username和password的数据也是post请求

猜你喜欢

转载自blog.csdn.net/LLLLLLLLLLe/article/details/109649718
今日推荐