How to upload a file in form-data format?

梦李
Tera Contributor

Hello all!

I've encountered a very challenging issue where I need to upload a file along with several field information to a third-party system from ServiceNow. I chose the content type as multipart/form-data, used JSON format for the field information part, and utilized ServiceNow's getContentStream() method for the file part. However, the third-party system receives only com.glide.communications.GlideScriptableInputStream@ for the file part instead of the actual file content. Below is my code. Could anyone suggest a way to resolve this? This has been confusing me for a long time. Thank you very much.

 

 var request = new sn_ws.RESTMessageV2();

   request.setHttpMethod('POST');

   request.setEndpoint('http://xxxx.xxx.xxxx/upload');

   request.setRequestHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"); 

   var boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; 

   var requestBody = [];

   var jsonData = {

       P_NO: "tre123",

       P_Num: "6"

   };

   requestBody.push("--"+ boundary);

   requestBody.push('Content-Disposition: form-data; name="jsonData"');

   requestBody.push('Content-Type: application/json');

   requestBody.push('');

   requestBody.push(JSON.stringify(jsonData));

   requestBody.push("--"+ boundary);

   requestBody.push('Content-Disposition: form-data; name="P_FILE"; filename="'+ fileName + '"');

   requestBody.push('Content-Type: application/octet-stream');

   requestBody.push('');

   requestBody.push(fileContentStream);

   requestBody.push("--"+ boundary + "--");

   request.setRequestBody(requestBody.join('\r\n'));

3 REPLIES 3

sreeram_nair
Tera Guru

The issue arises because ServiceNow's getContentStream() method returns a GlideScriptableInputStream, which needs to be properly converted into binary data to be included in the request body. Unfortunately, directly appending fileContentStream to the requestBody array won't work as expected for a multipart/form-data request.

Hopefully the following steps will help correct the code:

 

  • Use Base64 encoding to convert the file's content into a transferable format since ServiceNow doesn't natively support streaming raw binary data in the request body for multipart requests.
  • Include the Base64-encoded file data in the request body.
  • Use the appropriate Content-Transfer-Encoding for the file part.

 


ɪꜰ ᴍʏ ᴀɴꜱᴡᴇʀ ʜᴀꜱ ʜᴇʟᴘᴇᴅ ᴡɪᴛʜ ʏᴏᴜʀ Qᴜᴇꜱᴛɪᴏɴ, ᴘʟᴇᴀꜱᴇ ᴍᴀʀᴋ ᴍʏ ᴀɴꜱᴡᴇʀ ᴀꜱ ᴛʜᴇ ᴀᴄᴄᴇᴘᴛᴇᴅ ꜱᴏʟᴜᴛɪᴏɴ ᴀɴᴅ ɢɪᴠᴇ ᴀ ᴛʜᴜᴍʙꜱ ᴜᴘ.




ʙᴇꜱᴛ ʀᴇɢᴀʀᴅꜱ


ꜱʀᴇᴇʀᴀᴍ

Runjay Patel
Giga Sage

Hi @梦李 ,

 

Try below code.

var request = new sn_ws.RESTMessageV2();
request.setHttpMethod('POST');
request.setEndpoint('http://xxxx.xxx.xxxx/upload');

// Define the boundary for multipart data
var boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
request.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary); 

// Prepare JSON data for the request
var jsonData = {
    P_NO: "tre123",
    P_Num: "6"
};

// Read file content as a byte array
var attachmentSysId = '<attachment_sys_id>'; // Replace with your file's sys_id
var attachmentTableName = '<table_name>'; // Replace with the table associated with the file
var attachmentFileName = '<file_name>'; // Replace with the file name

var attachmentGR = new GlideSysAttachment().getContentStream(attachmentSysId);

// Convert file stream to Base64 encoded string
var fileContent = new GlideSysAttachment().getBase64Content(attachmentTableName, attachmentSysId);

// Build the multipart request body
var requestBody = [];

// JSON Part
requestBody.push("--" + boundary);
requestBody.push('Content-Disposition: form-data; name="jsonData"');
requestBody.push('Content-Type: application/json');
requestBody.push('');
requestBody.push(JSON.stringify(jsonData));

// File Part
requestBody.push("--" + boundary);
requestBody.push('Content-Disposition: form-data; name="P_FILE"; filename="' + attachmentFileName + '"');
requestBody.push('Content-Type: application/octet-stream');
requestBody.push('');
requestBody.push(fileContent); // Add the file content as Base64-encoded data

// End boundary
requestBody.push("--" + boundary + "--");

// Set the request body
request.setRequestBody(requestBody.join('\r\n'));

// Execute the request
try {
    var response = request.execute();
    var responseBody = response.getBody();
    var httpStatus = response.getStatusCode();
    gs.print("Response: " + responseBody);
    gs.print("HTTP Status: " + httpStatus);
} catch (ex) {
    gs.print("Error: " + ex.message);
}

 

-------------------------------------------------------------------------

If you found my response helpful, please consider selecting "Accept as Solution" and marking it as "Helpful." This not only supports me but also benefits the community.


Regards
Runjay Patel - ServiceNow Solution Architect
YouTube: https://www.youtube.com/@RunjayP
LinkedIn: https://www.linkedin.com/in/runjay

-------------------------------------------------------------------------

@Runjay Patel  Hi Runjay, Is there any way to send an attachment with setRequestBodyFromAttachment() method with multipart/form-data in scoped app ? 3rd Party app is expecting 'input_file' with attachment hence asking (Please refer attached screenshot from Postman).

 

var resultGr = new GlideRecord("sn_customerservice_case");
resultGr.addQuery("sys_id", current.table_sys_id);
resultGr.addQuery("account", '<account sys id>'); // running for specific account
resultGr.query();
if (resultGr.next()) {
var caseid = resultGr.sys_id.toString();
gs.info("Case sys id : " + caseid);
try {
var r = new sn_ws.RESTMessageV2('New Integration', 'UploadAttachment');
r.setRequestBodyFromAttachment(current.sys_id);
r.setRequestHeader("Content-Type", resultGr.content_type);
r.setStringParameterNoEscape('request_id', resultGr.correlation_id);

 

var response = r.execute();
var responseBody = response.getBody();
var httpStatus = response.getStatusCode();
gs.info("The value of the POST Response is " + httpStatus + "Body : " + responseBody);
} catch (ex) {
var message = ex.message;
}
}

 

Screenshot 2025-03-05 220953.png