tldr I'm having encoding issues when sending zip files as part of a multipart/form-data request body. Help please :/
I'm working on a bot that should be able to upload zip files to Slack (via their file api), but I'm running into some issues that I believe are related to encoding.
So, I'm creating my request body as follows:
var form_string = "\n--abcdefghijklmnop\nContent-Disposition: form-data; filename=\"" + filename + "\"; name=\"file\";\nContent-Type:application/octet-stream;\nContent-Transfer-Encoding:base64;\n\n" + data;
form_string += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"token\";\n\n" + token;
form_string += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"filetype\";\n\n" + filetype;
form_string += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"filename\";\n\n" + filename;
form_string += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"channels\";\n\n" + channel;
form_string += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"title\";\n\n" + title;
form_string += "\n--abcdefghijklmnop--";
var form = Buffer.from(form_string, "utf8");
var headers = {
"Content-Type": "multipart/form-data; boundary=abcdefghijklmnop",
"Content-Length": form.length,
"Authorization": "Bearer ....."
};
var options = {
"headers": headers,
"body": form
};
// using the sync-request node module.
var res = request("POST", url, options);
var res = request("POST", url, options);
(I've tried application/zip
and application/x-zip-compressed
as well. I've also tried both binary and base64 content transfer encodings.)
(And in case you're wondering, I need to make synchronous http requests...)
I created a really small zip file as a test. The base64 encoding of it is below:
UEsDBAoAAAAAAAqR+UoAAAAAAAAAAAAAAAAIABwAdGlueXppcC9VVAkAA1PBd1mDwXdZdXgLAAEE9QEAAAQUAAAAUEsDBAoAAAAAAAuR+Up6em/tAwAAAAMAAAAQABwAdGlueXppcC90aW55LnR4dFVUCQADVsF3WVzBd1l1eAsAAQT1AQAABBQAAABoaQpQSwECHgMKAAAAAAAKkflKAAAAAAAAAAAAAAAACAAYAAAAAAAAABAA7UEAAAAAdGlueXppcC9VVAUAA1PBd1l1eAsAAQT1AQAABBQAAABQSwECHgMKAAAAAAALkflKenpv7QMAAAADAAAAEAAYAAAAAAABAAAApIFCAAAAdGlueXppcC90aW55LnR4dFVUBQADVsF3WXV4CwABBPUBAAAEFAAAAFBLBQYAAAAAAgACAKQAAACPAAAAAAA=
What I'm getting from Slack seems to be similar to the original... maybe...
UEsDBAoAAAAAAArCkcO5SgAAAAAAAAAAAAAAAAgAHAB0aW55emlwL1VUCQADU8OBd1nCg8OBd1l1eAsAAQTDtQEAAAQUAAAAUEsDBAoAAAAAAAvCkcO5Snp6b8OtAwAAAAMAAAAQABwAdGlueXppcC90aW55LnR4dFVUCQADVsOBd1lcw4F3WXV4CwABBMO1AQAABBQAAABoaQpQSwECHgMKAAAAAAAKwpHDuUoAAAAAAAAAAAAAAAAIABgAAAAAAAAAEADDrUEAAAAAdGlueXppcC9VVAUAA1PDgXdZdXgLAAEEw7UBAAAEFAAAAFBLAQIeAwoAAAAAAAvCkcO5Snp6b8OtAwAAAAMAAAAQABgAAAAAAAEAAADCpMKBQgAAAHRpbnl6aXAvdGlueS50eHRVVAUAA1bDgXdZdXgLAAEEw7UBAAAEFAAAAFBLBQYAAAAAAgACAMKkAAAAwo8AAAAAAA==
Could someone explain what encoding is going on here and how I can correctly upload a file to Slack? Thanks!
How about following sample scripts? There are 2 patterns for this situation.
For this, I modified the method you are trying. You can upload the zip file by converting to the byte array as follows. At first, it builds form-data
. It adds the zip file converted to byte array and boundary
using Buffer.concat()
. This is used as body in request.
var fs = require('fs');
var request = require('request');
var upfile = 'sample.zip';
fs.readFile(upfile, function(err, content){
if(err){
console.error(err);
}
var token = '### access token ###';
var filetype = 'zip';
var filename = 'samplefilename';
var channel = 'sample';
var title = 'sampletitle';
var formString = "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"token\";\n\n" + token;
formString += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"filetype\";\n\n" + filetype;
formString += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"filename\";\n\n" + filename;
formString += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"channels\";\n\n" + channel;
formString += "\n--abcdefghijklmnop\nContent-Disposition: form-data; name=\"title\";\n\n" + title;
formString += "\n--abcdefghijklmnop\nContent-Disposition: form-data; filename=\"" + upfile + "\"; name=\"file\";\nContent-Type:application/octet-stream;\n\n";
var options = {
method: 'post',
url: 'https://slack.com/api/files.upload',
headers: {"Content-Type": "multipart/form-data; boundary=abcdefghijklmnop"},
body: Buffer.concat([
Buffer.from(formString, "utf8"),
new Buffer(content, 'binary'),
Buffer.from("\n--abcdefghijklmnop\n", "utf8"),
]),
};
request(options, function(error, response, body) {
console.log(body);
});
});
This is a simpler way than sample 1. You can use fs.createReadStream()
as a file for uploading to Slack.
var fs = require('fs');
var request = require('request');
request.post({
url: 'https://slack.com/api/files.upload',
formData: {
file: fs.createReadStream('sample.zip'),
token: '### access token ###',
filetype: 'zip',
filename: 'samplefilename',
channels: 'sample',
title: 'sampletitle',
},
}, function(error, response, body) {
console.log(body);
});
Both sample 1 and sample 2 can be uploaded zip file to Slack as follows. For both, even if filetype
is not defined, the uploaded file is used automatically as a zip file.
If I misunderstand your question, I'm sorry.