How to create multipart HTTP request in Node-RED

2019-08-18 07:04发布

问题:

I'm trying to send a multipart request with the following form-data:

------WebKitFormBoundaryjFqPRXY6RQpdTRvE
Content-Disposition: form-data; name="file"; filename="Sample.csv"
Content-Type: application/vnd.ms-excel


------WebKitFormBoundaryjFqPRXY6RQpdTRvE
Content-Disposition: form-data; name="data"; filename="blob"
Content-Type: application/json

{"name":"Sample5","type":"Csv","firstRowIsHeader":true,"columns":[{ ... }]}
------WebKitFormBoundaryjFqPRXY6RQpdTRvE--

The above data is normally being created and sent by a web service.
I'm trying to replicate the exact same HTTP request from Node-RED.
JSON data is already prepared so it's just creation of the multipart request.

I've tried using node-red-contrib-http-multipart but I'm not really sure how to configure it.

[{"id":"e0fde1bd.e0aa","type":"httpInMultipart","z":"fc689d44.1c52","name":"","url":"/test/upload","method":"post","fields":"[ { \"name\": \"file\", \"maxCount\": 1}, { \"name\": \"data\", \"maxCount\": 1} ]","swaggerDoc":"","x":1390,"y":820,"wires":[["d109ed84.14d1d","8a39aaa0.6934c8","d0bc5b20.45f3a8"]]},{"id":"a2318dfd.bae7d","type":"http in","z":"fc689d44.1c52","name":"","url":"/test/send","method":"get","upload":false,"swaggerDoc":"","x":1380,"y":680,"wires":[["d7cfc418.89eb98"]]},{"id":"14c992f3.8652ad","type":"http response","z":"fc689d44.1c52","name":"","x":1750,"y":680,"wires":[]},{"id":"d109ed84.14d1d","type":"debug","z":"fc689d44.1c52","name":"","active":true,"console":"false","complete":"true","x":1570,"y":780,"wires":[]},{"id":"8a39aaa0.6934c8","type":"http response","z":"fc689d44.1c52","name":"","statusCode":"","headers":{},"x":1570,"y":860,"wires":[]},{"id":"1a646c83.8da7d3","type":"debug","z":"fc689d44.1c52","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1790,"y":780,"wires":[]},{"id":"d7cfc418.89eb98","type":"template","z":"fc689d44.1c52","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<form action=\"/test/upload\" method=\"POST\" enctype=\"multipart/form-data\">\n  <div>\n    <input type=\"file\" name=\"file\">\n    <input type=\"submit\" value=\"Submit\">\n  </div>\n</form>","output":"str","x":1580,"y":680,"wires":[["2971b104.12737e","14c992f3.8652ad"]]},{"id":"d0bc5b20.45f3a8","type":"change","z":"fc689d44.1c52","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t   \"file\": req.files.file[0].buffer,\t   \"data\": \"test\"\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1620,"y":820,"wires":[["1a646c83.8da7d3"]]},{"id":"2971b104.12737e","type":"debug","z":"fc689d44.1c52","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":1730,"y":640,"wires":[]}]

Any kind of pointers on how to tackle the problem would be greatly appreciated.

回答1:

You don't need the multipart contribution node any more. For a while now the out of the box http input node has been able to handle multipart file uploads.

Set the method to POST and check the file uploads option. Files can be found in message.req.files.

If you are looking to send a multipart POST request from Node-RED to some service, then use the HTTP Request node. How is in the node info panel. Copied below, but best to check the node info panel itself as the text below may become out of date -

File Upload To perform a file upload, msg.headers["content-type"] should be set to multipart/form-data and the msg.payload passed to the node must be an object with the following structure:

 {
     "KEY": {
         "value": FILE_CONTENTS,
         "options": {
             "filename": "FILENAME"
         }
     } 
 } 

>

The values of KEY, FILE_CONTENTS and FILENAME should be set to the >appropriate values.

Here is a sample flow:

[{"id":"f7b0ae63.e74e5","type":"fileinject","z":"aacbc9d.6412c38","name":"","x":140,"y":160,"wires":[["5cb04348.8b9e2c"]]},{"id":"5cb04348.8b9e2c","type":"function","z":"aacbc9d.6412c38","name":"","func":"msg.headers = {\n    \"content-type\" : 'multipart/form-data'\n    };\nlet databuffer = msg.payload;\n\nmsg.payload = {\n    \"KEY\": {\n        \"value\": databuffer,\n        \"options\": {\n            \"filename\": \"myfile.png\"\n        }\n    }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":290,"y":160,"wires":[["f04784b6.9e3078"]]},{"id":"f04784b6.9e3078","type":"http request","z":"aacbc9d.6412c38","name":"","method":"POST","ret":"txt","paytoqs":false,"url":"myserver.mybluemix.net/file/input","tls":"","proxy":"","authType":"basic","x":450,"y":160,"wires":[["76de17b4.dc2de8"]]},{"id":"76de17b4.dc2de8","type":"debug","z":"aacbc9d.6412c38","name":"File has been sent","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":670,"y":160,"wires":[]}]


回答2:

It appears creating a multipart/form-data request directly on the HTTP request node is not yet supported. However, it's possible to manually create the multipart payload on a function node and feed it to the out-of-the-box HTTP request node.

Basically, feed to the HTTP request node a payload like so (a snippet from flows.nodered):

msg.headers = {
    "Content-Type": "multipart/form-data; boundary=------------------------d74496d66958873e"
}


msg.payload = '--------------------------d74496d66958873e\r\n'+
'Content-Disposition: form-data; name="select"\r\n'+
'\r\n'+
'true\r\n'+
'--------------------------d74496d66958873e\r\n'+
'Content-Disposition: form-data; name="print"\r\n'+
'\r\n'+
'true\r\n'+
'--------------------------d74496d66958873e\r\n'+
'Content-Disposition: form-data; name="file"; filename="'+msg.filename+'"\r\n'+
'Content-Type: application/octet-stream\r\n'+
'\r\n'+
msg.payload+'\r\n'+
'--------------------------d74496d66958873e--\r\n';


return msg;

The format of the multipart payload is thoroughly discussed in discourse.nodered.
A sample flow is also provided in flows.nodered.