1.知识必备

(1)当服务器响应不同文件类型时,需要设置响应报文头,让浏览器选择相应的编码数据。

常用对照表HTTP Mime-type:
https://tool.oschina.net/commons

思路:根据访问的路径来提取后缀名,再根据后缀名设置相应的 Content-Type

(2)请求路径不存在时设置返回的状态码

res.statusCode = 404
res.statusMessage = 'Not found'

(3)需要用到path模块和fs模块拼接路径即读取文件

2.模拟Apache服务器(一)

共封装了4个方法;
getFileType(url):根据url获取文件类型
setContentType(res,fileType):根据文件类型设置Mime-type
renderFile(res,url):根据路径读取相应的文件并返回给客户端
troubleShooting(res,url,fileType):错误处理函数

源码:

// 引入http模块
const http = require("http");
//引入fs模块
const fs = require('fs');
//引入path模块 (拼接路径)
const path = require('path');

// 创建一个服务器
var server = http.createServer((req,res)=>{
    //获取文件类型
    var fileType = getFileType(req.url)
    if(!fileType) fileType = "html"
    //设置ContentType
    setContentType(res,fileType)
    //读取文件并返回
    renderFile(res,req.url)
});


// 监听接口,需运行此文件,浏览器才能正常访问 "127.0.0.1"
server.listen(80,"127.0.0.1",function(err){
    if(err){
        throw err;
    }
    console.log('Server running at http://127.0.0.1:80/');
});


//根据url获取后缀名
function getFileType(url){
    //定义文件类型
    var fileType = ""
    //获取 "." 在url中的下标位置
    var index = url.lastIndexOf('.')
    if(index>=0){
        // xxx.jpg => jpg
        fileType = url.substring(index+1)
    }
    return fileType
}

//根据后缀名设置响应头
function setContentType(res,fileType){
    var contrast = {
        html:"text/html;charset=utf-8",
        css:"text/css",
        txt:"text/plain;charset=utf-8",
        jpg:"image/jpeg",
        png:"image/png",
        jpeg:"image/jpeg",
        svg:"text/xml",
        gif:"image/gif",
        mp3:"audio/mp3",
        mp4:"video/mpeg4",
        pdf:"application/pdf"
    }
    //设置默认的ContentType为text/html;charset=utf-8
    var ContentType = "text/html;charset=utf-8"
    //如果文件类型为空,则默认设置为html格式
    if(!fileType) fileType = "html"
    //匹配文件类型
    Object.keys(contrast).forEach((key) => {
        if(key === fileType){
            ContentType = contrast[key]
            //跳出遍历
            return false
        }
    })
    //设置响应头
    res.setHeader("Content-Type",ContentType)
}

//封装读取文件的函数 (依赖path和fs模块)
function renderFile(res,url){
    //如果访问根目录
    if(url=='/'){
        url = '/index.html';
    }
    //设置静态文件根目录
    var root = "www"
    //拼接路径
    var filePath = path.join(__dirname,root,url)
    //读取文件
    fs.readFile(filePath,function(err,data){
        if(err){
            //处理异常
            troubleShooting(res,url,fileType)
        }else{
            //返回文件内容
            res.end(data)
        }
    })

}

//封装处理错误的函数
function troubleShooting(res,url,fileType){
    console.log(url+"文件不存在")
    //设置返回的状态码
    res.statusCode = 404
    res.statusMessage = 'Not found'
    //根据文件类型返回不同的数据
    if(fileType){
        res.end("")
    }else{
        //返回404页面
        res.end("页面不存在")
    }
}

3.模拟Apache服务器(二)

(1)文件类型多种多样,每样都要手动设置Mime-Type费时费力,可以使用第三方模块来完成
这个模块就是 mime

安装mime模块

npm i mime

mime的作用就是根据url的后缀,返回对应的Content-Type

const mime = require("mime")
console.log(mime.getType("xxx.css")) // text/css
console.log(mime.getType("/")) // null

完整代码:

const http = require('http');
const path = require('path');
const fs = require('fs');
const mime = require('mime');

var server = http.createServer((req,res)=>{
    var contentType = mime.getType(req.url);
    res.setHeader('Content-Type',contentType);
    returnFile(req.url,res);
})



//根据url和文件类型返回对应的文件
function returnFile(url,res){
    //如果访问根目录
    if(url=='/'){
        url = '/index.html';
    }
    var result = path.join(__dirname,'www',url);
    fs.readFile(result,function(err,data){
        if(err){
            res.end('页面不存在');
        }
        res.end(data);
    })
}

server.listen(80,"127.0.0.1",function(err){
    if(err){
        throw err;
    }
    console.log('Server running at http://127.0.0.1:80/');
})
01-16 06:24