Node之http模块

110 阅读3分钟

Node之http模块

const http = require('http');
const request = http.request('http://duyi.ke.qq.com/', {
    method: 'GET'
}, resp => {
    console.log('状态码', resp.statusCode);
    console.log('响应头', resp.headers);
    let result = ''
    resp.on('data', chunk => {
        // console.log(chunk.toString('utf-8'))
        result += chunk.toString('utf-8');
    })
    resp.on('end', chunk => {
        console.log(result)
    })
})
request.end()//必须给一个结束的消息

http 模块是在 net 模块之上建立的,它省去了 socket 的管理编写和消息格式的编写。有两个 API ,一个是创建客户端,一个是创建服务器。客户端一个是响应自己搭建的服务器,一个是响应远程服务器。
http.request() 里面可以传入三个参数。第一个是路径,第二个是配置对象,第三个是回调函数,拿到响应后的结果。
类似上面的例子,创建一个客户端。我们可以直接解析响应结果,不用像之前再进行手动书写。必须写响应体,使用 write 和 end 。可以只写 end ,但不能不写。如果不写会导致服务器一直等待,不会返回响应结果。
响应体一定要从流里面读取,因为有可能流的内容很多,如果直接读取可能导致无法读取,所以采用流的方式读取。

const url = require('url')
function handleReq(req){
    console.log('有请求来了')
    const urlObj = url.parse(req.url)
    console.log('请求路径', urlObj)
    console.log('请求方法', req.method)
    console.log('请求头', req.headers)
    let body = ''
    req.on('data', chunk => {
        body += chunk.toString('utf-8')
    })
    req.on('end', () => {
        console.log('请求体', body)
    })
}
const server = http.createServer((req, res) => {
    handleReq(req)
    res.setHeader('a', '1')
    res.setHeader('b', '2')
    res.statusCode = 404
    res.write('你好!')
    res.end()
})
server.listen(8000)
server.on('listening', () => {
    console.log('服务器启动成功')
})

同样,可以创建一个服务器。可以传配置对象和回调函数。回调函数表示请求已经到达。使用 createServer 来创建,req 表示收到的请求,res 表示返回的响应结果。同样,请求体使用流来进行传输。
不管是客户端还是服务器,收到消息的都是 IncomingMessage 对象,客户端从响应拿到消息,服务器从请求拿到消息。客户端发出请求是 ClientRequest 对象,服务器响应结果是 ServerResponse 对象。注意一定要分清。

const path = require('path')
const URL = require('url')
const fs = require('fs')
//搭建静态资源服务器,就是把请求路径和文件路径对应
/**
 * 获取文件信息
 * @param {*} filename 
 */
async function getStat(filename) {
    try{
        return await fs.promises.stat(filename)
    }
    catch{
        return null;
    }
}
/**
 * 处理文件内容
 * @param {*} url 
 */
async function getFileContent(url) {
    const urlObj = URL.parse(url)
    let filename = path.resolve(__dirname,'myfiles/public', urlObj.pathname.substring(1))
    let stat = await getStat(filename)
    if(!stat){
        return null
    }else if(stat.isDirectory()){
        filename = path.resolve(__dirname,'myfiles/public', urlObj.pathname.substring(1), 'index.html')
        stat = await getStat(filename)
        if(!stat){
            return null
        }else{
            return await fs.promises.readFile(filename)
        }
    }else{
        return await fs.promises.readFile(filename)
    }
}
async function handler(req, res) {
    const info = await getFileContent(req.url)
    if(info){
        res.write(info)
    }else{
        res.statusCode = 404
        res.write('Resource is not exist')
    }
    res.end()
}
const server = http.createServer(handler)
server.listen(8000)
server.on('listening', () => {
    console.log('服务器启动成功')
})

我们要搭建一个静态资源服务器,需要根据文件路径来得到请求路径。先创建一个处理函数,设置监听端口。然后通过 getFileContent 请求路径得到本地文件内容,通过 url 地址进行解析,解析成对象。再通过一个函数 getStat 进行文件是否存在的判断。如果文件存在返回状态,否则返回 null 。
在 getFileContent 函数里得到状态以后,如果文件不存在返回 null ,接着判断是否为目录,如果是目录接着进行判断,找到文件路径呢就返回,不是目录则返回文件路径。
在 handler 函数里拿到文件内容以后,如果有内容就响应内容,没有内容就返回 404 错误。这样就实现了本地服务器的功能。
更改静态资源是不需要重启服务器的。注意实现过程中的异步函数,promise 一定返回 true ,忘了加 await 就会导致一直返回为 true 。