nodejs学习笔记 | 用nodejs创建一个web服务器

264 阅读3分钟

| 实现目标

  1. 可以访问网站
  2. 可以下载web服务器上面的文件

app.js

var http = require('http');
var fs = require('fs');
const common = require('./module/common'); // 引入公共方法
const path = require('path');
const url = require('url');
http.createServer(function (request, response) {
    let pathName = url.parse(request.url).pathname;
    pathName = pathName == '/' ? '/index.html' : pathName;
    if (pathName != '/favicon.ico') {
        fs.readFile('./static' + pathName, async (err, data) => {
            // 获取后缀名 如.css .js
            let extname = await common.getAllMime(path.extname(pathName));
            let code = 200,
                resData = data;
            if (err) {
                code = 404;
                resData = '页面不存在';
            }
            // 根据不同后缀返回不同的extname
            response.writeHead(code, {
                'Content-Type': extname + ';charset="utf-8"',
            });
            response.end(resData);
        });
    }
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');

/module/common.js

// 全部类型版本
// Mime.json 包含所有的文件类型的映射关系,需要自己建一个
const fs = require('fs');
exports.getAllMime = function (extname) {
    // 这是异步读取方法,需要返回promise,
    // 如果不使用异步读取,可以使用readFileSync()
    return new Promise((resolve, reject) => {
        let mimeObj = null;
        fs.readFile('./data/Mime.json', (err, data) => {
            if (err) {
                reject(err);
                return;
            }
            mimeObj = JSON.parse(data)[extname];
            resolve(mimeObj);
        });
    });
};

当我们使用传参的url时,比如
<http://127.0.0.1:8081/login.html?2323>

此时就会报错页面不存在
因此我们获取pathName的时候应该只需获取login.html,过滤其他没有用的参数
引入url模块,并使用该模块的parse方法返回的对象里的pathname 即可

const url = require('url');
let pathName = url.parse(request.url).pathname;

HTTP content-type资料

| 封装静态web服务

1.删除common.js, 创建routes.js

const fs = require('fs');
const path = require('path');
const url = require('url');
// Mime.json 包含所有的文件类型的映射关系,需要自己建一个
const getAllMime = function (extname) {
    // 这是异步读取方法,需要返回promise,
    // 如果不使用异步读取,可以使用readFileSync()
    return new Promise((resolve, reject) => {
        let mimeObj = null;
        fs.readFile('./data/Mime.json', (err, data) => {
            if (err) {
                reject(err);
                return;
            }
            mimeObj = JSON.parse(data)[extname];
            resolve(mimeObj);
        });
    });
};
/**
 * 请求封装
 * @param {*} request   服务请求
 * @param {*} response  服务响应
 * @param {string} staticPath 静态资源路径
 */
exports.static = function (request, response, staticPath) {
    let pathName = url.parse(request.url).pathname;
    pathName = pathName == '/' ? '/index.html' : pathName;
    if (pathName != '/favicon.ico') {
        fs.readFile(staticPath + pathName, async (err, data) => {
            // 获取后缀名 如.css .js
            let extname = await getAllMime(path.extname(pathName));
            let code = 200,
                resData = data;
            if (err) {
                code = 404;
                resData = '页面不存在';
            }
            // 根据不同后缀返回不同的extname
            response.writeHead(code, {
                'Content-Type': extname + ';charset="utf-8"',
            });
            response.end(resData);
        });
    }
};

app.js

var http = require('http');
var routes = require('./module/routes');
http.createServer(function (request, response) {
    routes.static(request, response, './static');
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');

| 路由判断

route.js

const fs = require('fs');
const path = require('path');
const url = require('url');
// Mime.json 包含所有的文件类型的映射关系,需要自己建一个
const getAllMime = function (extname) {
    // 这是异步读取方法,需要返回promise,
    // 如果不使用异步读取,可以使用readFileSync()
    let data = fs.readFileSync('./data/Mime.json');
    let mimeObj = JSON.parse(data.toString());
    return mimeObj[extname];
};
/**
 * 请求封装
 * @param {*} request   服务请求
 * @param {*} response  服务响应
 * @param {string} staticPath 静态资源路径
 */
exports.static = function (request, response, staticPath) {
    let pathName = url.parse(request.url).pathname;
    pathName = pathName == '/' ? '/index.html' : pathName;
    if (pathName != '/favicon.ico' && pathName != '/null') {
        try {
            let result = fs.readFileSync('./' + staticPath + pathName);
            if (result) {
                // 获取后缀名 如.css .js
                let mime = getAllMime(path.extname(pathName));
                response.writeHead(200, {
                    'Content-Type': mime + ';charset="utf-8"',
                });
                response.end(result);
                return true;
            }
        } catch (error) {
            return false;
        }
    }
};

app.js

const http = require('http');
const routes = require('./module/routes');
const url = require('url');
http.createServer(function (request, response) {
    let result = routes.static(request, response, 'static');
    if (result) return;
    
    // 路由判断
    let pathName = url.parse(request.url).pathname;
    if (pathName == '/login') {
        response.writeHead(200, {
            'Content-Type': 'text/html' + ';charset="utf-8"',
        });
        response.end('执行登录');
    } else {
        response.writeHead(404, {
            'Content-Type': 'text/html' + ';charset="utf-8"',
        });
        response.end('页面不存在');
    }
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');

| EJS模板引擎

EJS是后台模板引擎,可以处理页面数据绑定,是一个第三方模块
EJS有利于SEO,不利于前后端分离

1.安装

npm install ejs --save

2.创建一个login.ejs文件

view/login.ejs

<!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>login</title>
    </head>
    <body>
        <h1>我是登录页面</h1>

        <!--  接收ejs传递的数据 -->
        <p><%=msg %></p>
    </body>
</html>

3.app.js引用ejs模板引擎

const http = require('http');
const routes = require('./module/routes');
const url = require('url');
// 引入ejs
const ejs = require('ejs');
http.createServer(function (request, response) {
    let result = routes.static(request, response, 'static');
    if (result) return;
    // 路由判断
    let pathName = url.parse(request.url).pathname;
    if (pathName == '/login') {
   
       // 使用ejs传递数据
        let msg = '我是数据库获取的数据';
        ejs.renderFile('./views/login.ejs', { msg }, (err, data) => {
            response.writeHead(200, {
                'Content-Type': 'text/html' + ';charset="utf-8"',
            });
            response.end(data);
        });
    } else {
        response.writeHead(404, {
            'Content-Type': 'text/html' + ';charset="utf-8"',
        });
        response.end('页面不存在');
    }
}).listen(8081);
console.log('Server running at http://127.0.0.1:8081/');

4.结果

image.png

| get 和 post请求

get请求

let { pathname, query } = url.parse(request.url); // 返回的是字符串
// let {query } = url.parse(request.url, true); // 返回的是对象

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

在url上传值

http://127.0.0.1:8081/get?name=%E4%B8%89%E6%9C%A8&age=18

打印结果

image.png

post请求

if (pathname == '/postData') {
        let postData = '';
        
        // post数据接收中
        request.on('data', postDataChunk => {
            postData += postDataChunk;
        });
        // post数据接收完毕
        request.on('end', function () {
            console.log(postData, '----postData');
        });
    } 

触发post请求

<!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>login</title>
    </head>
    <body>
        <h1>我是登录页面</h1>
        <!-- 触发post -->
        <form action="/postData" method="post">
            <input type="text" name="username" required="required" />
            <input type="password" name="password" required="required" />
            <input type="submit" value="submit">
        </form>
    </body>
</html>