• Node学习十四 —— 使用node创建HTTP请求


    创建HTTP连接

    Node擅长处理I/O操作,所以它不仅合适提供HTTP服务,也适合使用这些服务。接下来你将学习使用http模块和第三方模块执行和控制http请求。

    HTTP协议中,有两个重要的属性:URL和方法。最常见的是GET、POST方法,还有PUT等别的方法。

    一、创建GET请求

    const http = require('http');
    
    const options = {
        host: 'localhost',
        port: 1234,
        path: '/'
    }
    
    http.get(options, (res) => {
        console.log(res);
    })
    

    在上面这个例子中,使用TCP端口1234向主机名localhost和路径/执行GET请求(localhost:1234/)。回调函数会在服务器响应到达的时候处理响应对象。

    二、使用其他HTTP动词

    2.1 发送POST请求

    http.get 是通用的 http.request 的快捷方式,其选项如下:

    • host——请求目标的主机名或者IP地址
    • port——远程服务器的TCP端口号
    • method——指定HTTP请求方法的字符串,值就是GET/POST/PUT/PATCH/DELETE等关键词。
    • path——请求的路径,可以包含一个查询字符串和一个分隔符:/index?id=1
    • headers——配置请求头

    http.request 方法会返回一个 http.ClientRequest 对象,它是一个可写流,可以使用这个流发送数据,所发送的数据是请求主体数据的一部分,当完成向请求主体中写入数据时,要结束数据流来终止请求。

    完整的请求,你可以这么写:

    const http = require('http');
    
    const options = {
        host: 'localhost',
        port: 1234,
        path: '/',
        method: 'POST'
    }
    
    // 发送请求,监听响应
    const req = http.request(options, (response) => {
        console.log(response.statusCode);
        console.log(response.headers);
        response.setEncoding('utf-8');
        response.on('data', (chunk) => {
            console.log('BODY : ' + chunk);
        })
    })
    
    req.write('This is a request');
    req.end();
    

    http.request 返回ClientRequest对象,可以通过req.write()方法将请求主体写入该对象,可以传入一个经过编码的字符串,或者缓冲区。必须使用end()去结束请求,不然会被认为请求不完整,从而不会处理该请求。

    如果服务器正常工作,会返回一个响应,客户端接收到响应触发response事件:

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

    2.2 查看响应对象

    响应对象是ClientResponse的一个实例,主要属性有:

    • statusCode——HTTP状态码
    • httpVersion——HTTP版本号
    • headers——响应头

    2.3 获取响应主体

    响应主体并不会在请求的response事件发生时出现,而是需要监听data事件:

    http.request(options, (response) => {
        response.setEncoding('utf8');
        response.on('data', (data) => {
            console.log(data);
        })
    })
    

    响应主题可以是一个缓冲区,但是如果指定了编码格式,那么就是一个编码字符串了。

    2.4 以流的方式传送响应主体

    HTTP响应是一个可读流,表示响应主体数据流。可以将一个可读流送入一个可写流中,例如一个HTTP请求或者一个文件:

    const http = require('http');
    const fs = require('fs');
    const options = {
        host: 'localhost',
        port: 1234,
        path: '/',
        method: "GET"
    }
    
    const file = fs.createWriteStream('./test.text');
    
    http.request(options, (res) => {
        res.pipe(file);
    }).end();
    

    上面创建了一个可写文件流,并将响应体写入文件。

    当响应到达,文件流打开,响应体写入;当响应主体结束的时候,文件流也结束,文件流被关闭。

    三、使用 HTTP.Agent 维护套接字

    在创建HTTP请求的时候,Node在内部使用了一个代理。

    代理是Node中的一种实体,该实体用来给你创建请求,它负责维护一个套接字池,对指定的主机名和端口对,套接字池中包含已经被打开但是未被使用的连接。

    当出现新的HTTP请求时,代理要求连接保持活跃状态;当请求结束,并且在套接字上没有额外的请求等待释放时,套接字就会被关闭,而不用手动关闭。

    当创建了一个请求并选择了一个可用的套接字,或者为该请求创建了一个新的连接时,http.ClientRequest 会发射socket事件。在请求结束之后,套接字会在发射close事件或agentRemove事件时从套接字池中被删除。

    四、应用第三方请求模块简化HTTP请求

    Node的HTTP客户端非常强大,但是用起来很麻烦:

    • 必须提供一个配置对象,需要所有选项,包括被分割的URL。
    • 如果希望处理响应体,需要专门获取响应体。
    • 如果是重定向响应,需要人工处理该响应。

    通过使用 request 模块可以简化操作。

    1. 安装和应用 request 模块

    使用npm在当前目录下安装该模块

    npm install request

    然后使用:

    const r = require('request');
    

    之后只需要提供URL和回调就可以创建请求了

    request('localhost:1234', (error,res,body) => {
        ...
    })
    

    如果按上述代码发送请求,默认为GET请求吗,如果想要使用其他HTTP动词,例如post:request.put(url);

    还可以用option对象来替代URL,可选参数可以查看官方文档。

    2. 创建测试服务器

    1. 服务器端代码
    const http = require('http');
    const server = http.createServer();
    
    // 监听请求
    server.on("request", (req, res) => {
        // 回送一个消息
        const printBack = function () {
            res.writeHead(200, {
                'Content-Type': 'text/plain'
            });
            res.end(JSON.stringify({
                URL: req.url,
                method: req.method,
                Headers: req.headers
            }))
        }
    
        // 路由
        switch (req.url) {
            // 重定向
            case '/redirect':
                res.writeHead(301, { "Location": '/' })
                res.end();
                break;
    
            // 打印请求体
            case '/print/body':
                req.setEncoding('utf8');
                let body = "";
                req.on('data', (data) => {
                    body += data;
                });
                // 结束之后,响应以发送body结束
                req.on('end', () => {
                    res.end(JSON.stringify(body));
                })
                break;
    
            // 默认
            default:
                printBack();
                break;
        }
    })
    
    server.listen(1234);
    
    1. 客户端代码
    const request = require('request');
    const inspect = require('util').inspect;
    
    request.get('http://localhost:1234/print/body', (err, res, body) => {
        if(err) {
            throw err;
        }
        console.log(inspect({
            err: err,
            res: {
                statusCode: res.statusCode
            },
            body: JSON.parse(body)
        }))
    })
    

    3. 跟随重定向

    request 的特性之一是它在默认情况下能够跟随重定向。可以用上面的代码来观察这个特征:

    当请求路径为/redirect时,可以用301重定向响应码做出响应。可以用客户端来查看跟随上述URL的请求:

    将请求路径修改为/redirect,可以在客户端看到返回信息中路径为/而不是/redirect

    如果你希望发生重定向的时候得到通知,可以把请求选项中的followRedirect设置为 false 。

    4. 使用option

    const options = {
        url: 'http://localhost:1234',
        method: 'POST',
        headers: {
            '...': '...'
        }
    }
    request(options, function(err, res, body){
        ...........
    })
    

    5. 对请求体进行编码

    有时候需要在请求主体上发送一些数据,可以使用表单编码对请求体进行编码:

    const body = {
        a: 1,
        b: 2
    };
    const options = {
        url: '...',
        form: body
        // 还可以采用json编码,如下:
        // json: body
    }
    

    6. 流式传送

    请求返回的是一个客户端请求对象,可以将该对象传入可写流当中,甚至可以将请求对象传入另一个请求。

    1. 传入文件

      request.get('...').pipe(fs.createWriteStream('...'));
      
    2. 传入另一个请求

      request.get('...').pipe(request.post('...'));
      
  • 相关阅读:
    YOLOV5---自己数据集制作
    输入输出系统
    【算法】算法题-20231118
    RTL8380M管理型交换机系统软件操作指南一:端口配置
    任何人不知道这款超实用的配音软件,我都会伤心的OK?
    ahooks 是怎么处理 DOM 的?
    刷新AI作图速度,最快的开源Stable Diffusion出炉
    JAVA中简单的for循环竟有这么多坑,你踩过吗
    java计算机毕业设计线上竞赛训练系统录屏源程序+mysql+系统+lw文档+远程调试
    如何在 Cypress 测试中通过 URL 下载文件?
  • 原文地址:https://blog.csdn.net/qq_51574759/article/details/127037826