发送 HTTP/2 POST 请求 NodeJS

Posted

技术标签:

【中文标题】发送 HTTP/2 POST 请求 NodeJS【英文标题】:Sending HTTP/2 POST request NodeJS 【发布时间】:2018-07-07 14:10:59 【问题描述】:

我正在尝试弄清楚如何使用 NodeJS 发送 HTTP/2 POST 请求。我与文档中的示例相去甚远:

const http2 = require('http2');
const fs = require('fs');
const client = http2.connect('https://localhost:8443', 
  ca: fs.readFileSync('localhost-cert.pem')
);
client.on('error', (err) => console.error(err));
client.on('socketError', (err) => console.error(err));

const req = client.request( ':path': '/' );

req.on('response', (headers, flags) => 
  for (const name in headers) 
    console.log(`$name: $headers[name]`);
  
);

req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) =>  data += chunk; );
req.on('end', () => 
  console.log(`\n$data`);
  client.close();
);
req.end();

但我不清楚如何实际设置数据以作为 POST 发送。

【问题讨论】:

【参考方案1】:

如果您需要将对象作为 json 发布 - 您应该将其字符串化并包装在缓冲区中。以下是适用于我的代码:

const http2 = require('http2');

const post = (url, path, body) => new Promise((resolve) => 
    const client = http2.connect(url);

    const buffer = Buffer.from(JSON.stringify(body));

    const req = client.request(
        [http2.constants.HTTP2_HEADER_SCHEME]: "https",
        [http2.constants.HTTP2_HEADER_METHOD]: http2.constants.HTTP2_METHOD_POST,
        [http2.constants.HTTP2_HEADER_PATH]: `/$path`,
        "Content-Type": "application/json",
        "Content-Length": buffer.length,
    );

    req.setEncoding('utf8');
    let data = [];
    req.on('data', (chunk) => 
        data.push(chunk);
    );
    req.write(buffer);
    req.end();
    req.on('end', () => 
        resolve( data: data.join("") );
    );
);

【讨论】:

只要我将连接更改为包含一个空字符串分隔符:data.join(""),上面的示例就适用于我。否则它最终会在结果中添加额外的逗号。【参考方案2】:

在到处拼凑一点点信息之后,我终于设法解决了这个问题。这是一个模板示例。关键在 req.write() 中。老实说,我在任何地方都找不到关于如何包含身体的直接答案。几乎每个例子都没有实体!希望这对其他人有帮助。注意:这是 Node-red,因此是 global.get 语句,但也可以通过将它们更改为 require('module') 来工作:

const fs = global.get('fs');
const http2 = global.get('http2');

fs.readFile('turn-off-the-desklight.raw', function(err, content)
    if(err)
        node.send(err);
    
    var metadata = JSON.stringify(
      
        "context": [   
            
                "header": 
                    "namespace": "SpeechRecognizer",
                    "name": "RecognizerState"
                ,
                "payload": 

                
            ,
            
                "header": 
                    "namespace": "Speaker",
                    "name": "VolumeState"
                ,
                "payload": 
                    "volume": 10,
                    "muted": false
                
            ,
            
                "header": 
                    "namespace": "Alerts",
                    "name": "AlertsState"
                ,
                "payload": 
                    "allAlerts": [],
                    "activeAlerts": []
                
            ,
            
                "header": 
                    "namespace": "SpeechSynthesizer",
                    "name": "SpeechState"
                ,
                "payload": 
                    "token": "",
                    "offsetInMilliseconds": 0,
                    "playerActivity": "FINISHED"
                
            ,
            
                "header": 
                    "namespace": "AudioPlayer",
                    "name": "PlaybackState"
                ,
                "payload": 
                    "token": "",
                    "offsetInMilliseconds": 0,
                    "playerActivity": "IDLE"
                
            
        ],  
        "event":   
            "header":   
                "namespace": "SpeechRecognizer",  
                "name": "Recognize",  
                "messageId": "1eff3c5e-02e3-4dd3-9ca0-7c38937f005f",  
                "dialogRequestId": "a905c2bb-1bbd-45cf-9f85-6563d2546492"
            ,  
            "payload":   
                "profile": "FAR_FIELD",
                "format": "AUDIO_L16_RATE_16000_CHANNELS_1"
              
          
    );
    var data = "--this-is-my-boundary-for-alexa\r\n";
    data += 'Content-Disposition: form-data; name="metadata"\r\n';
    data +='Content-Type: application/json; charset=UTF-8\r\n\r\n';
    data += metadata;
    data += "\r\n";
    data += "--this-is-my-boundary-for-alexa\r\n";
    data += "Content-Disposition: form-data; name=\"audio\"\r\n";
    data += "Content-Type:application/octet-stream\r\n\r\n";
    var payload = Buffer.concat([
            Buffer.from(data, "utf8"),
            new Buffer(content, 'binary'),
            Buffer.from("\r\n--this-is-my-boundary-for-alexa\r\n", "utf8"),
    ]);

    const client = global.get('alexaClient');

    client.on('error', (err) => node.send(payload:err));
    client.on('socketError', (err) => node.send(payload:err));

    var request = 
        ':method' : 'POST',  
        ':scheme' : 'https',  
        ':path' : '/v20160207/events',
        'authorization' : 'Bearer <valid token>',
        'content-type' : 'multipart/form-data; boundary=this-is-my-boundary-for-alexa'
    ;

    var req = client.request(request);

    req.on('response', (headers, flags) => 
        for (const name in headers) 
            if(name === ':status') 
                node.send(payload:`$name: $headers[name]`);
            
        
    );

    req.on('error', function(err) 
      node.send(err);
    );

    req.setEncoding('utf8');
    let outdata = '';
    req.on('data', (chunk) =>  outdata += chunk; );
    req.on('end', () => 
        node.send(payload:outdata);
    );

    req.write(payload);

    req.end();  
); 

【讨论】:

无论我做什么,在 req.write 和 req.end 之后,我都没有看到数据被发送到服务器。服务器甚至在另一端指示缓冲区为空。 @Nick 打开另一个问题并发布您的代码,然后链接回此处。我去看看。 谢谢***.com/questions/49583948/… @JohnSmith 感谢您提供的代码。您能否将音频保存到本地磁盘?我想将响应从语音转换为文本。【参考方案3】:

您可以向服务器发送数据,也可以从服务器接收数据。

1) 客户

const http2 = require('http2');
var port = 15000;
const client = http2.connect('https://localhost:15000/');

// Must not specify the ':path' and ':scheme' headers
// for CONNECT requests or an error will be thrown.
var body = "Hello, I am babatman";
const req = client.request(
  ':method': 'POST',
  ':authority': `localhost:$port`, 
  'body': body
);
req.on('response', (headers) => 
  console.log(headers[http2.constants.HTTP2_HEADER_STATUS]);
);
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => data += chunk);
req.on('end', () => 
  console.log(`The server says: $data`);
  client.close();
);

2) 服务器

app.use(async ctx => 
console.log(ctx.request);

ctx.response.status = 201;
ctx.body = "hello";
console.log("Response 201 was send.")
);

【讨论】:

以上是关于发送 HTTP/2 POST 请求 NodeJS的主要内容,如果未能解决你的问题,请参考以下文章

nodejs post请求 怎么用url

如何使用NodeJS上的本机Ajax发送Post by Post请求

nodejs:app.use处理post请求

通过 Observable 从 Angular 向 nodejs 发送 POST 请求

nodejs post 请求soap 报错.大神求助

NodeJS - 只有 OPTIONS 请求被发送到 REST API,POST 或 GET 不跟随(Cloudflare)