40

I'm trying to send a HTTP POST to a device on my network. I want to send four specific bytes of data to the device unfortunately I only seem to be able to send strings to the device. Is there anyway to send raw binary using javascript?

Here's the script I'm using to do the POST, it currently doesn't run unless I put a string in the data field. Any ideas?

(function ($) {
   $.ajax({
      url: '<IP of Address>',
      type: 'POST',
      contentType: 'application/octet-stream',

      //data:'253,0,128,1',
      data:0xFD008001,

      crossDomain: true
   });
})(jQuery);
raina77ow
  • 103,633
  • 15
  • 192
  • 229
user2984509
  • 403
  • 1
  • 4
  • 6

4 Answers4

53

By default, jQuery serializes the data (passed in data property) - and it means 0xFD008001 number gets passed to the server as '4244668417' string (10 bytes, not 4), that's why the server treats it not as expected.

It's necessary to prevent such behaviour by setting $.ajax property processData to false:

By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded". If you want to send a DOMDocument, or other non-processed data, set this option to false.

... but that's only part of the whole story: XMLHttpRequest.send implementation has its own restrictions. That's why your best bet, I suppose, is to make your own serializer using TypedArrays:

// Since we deal with Firefox and Chrome only 
var bytesToSend = [253, 0, 128, 1],
    bytesArray = new Uint8Array(bytesToSend);

$.ajax({
   url: '%your_service_url%',
   type: 'POST',
   contentType: 'application/octet-stream',  
   data: bytesArray,
   processData: false
});

Or without using jQuery at all:

var bytesToSend = [253, 0, 128, 1],
    bytesArray = new Uint8Array(bytesToSend);

var xhr = new XMLHttpRequest();
xhr.open('POST', '%your_service_url%');
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.send(bytesArray);
raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • 1
    I get `ArrayBuffer is deprecated in XMLHttpRequest.send(). Use ArrayBufferView instead.` but then get a `ReferenceError: ArrayBufferView is not defined` – Musa Nov 13 '13 at 17:42
  • Yes, I've rewritten this to not use `ArrayBuffer`; typedArray are actually supported both by Chrome and Firefox as `xhr.send` param. – raina77ow Nov 13 '13 at 17:45
  • Thanks for this! I'm quite new to javascript so I was thinking there was something simple I was missing. Your explanation definitely went above and beyond. Thanks! – user2984509 Nov 13 '13 at 17:47
  • There's no need for your loops above. The typed array constructors accept array-like objects and do the loop for you. So just `var bytesArray = new Uint8Array(bytesToSend);` is all you need. [Details here](http://www.ecma-international.org/ecma-262/7.0/index.html#sec-typedarray-object), but I didn't want to edit that in unilaterally. – T.J. Crowder Aug 05 '16 at 16:47
  • I see your point, but what about browser support? I've assumed using `new TypedArray(plainArray)` construct is only possible in the browsers that support `TypedArray.from(plainArray)`, and judging from [this docpage](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from), IE and Safari don't allow that. – raina77ow Aug 05 '16 at 21:11
  • Ah, just noticed the original recipe (using `ArrayBufferView` as `xhr.send` param) was only for Firefox and Chrome... And, surprise, surprise, it looks like it's the same thing in Aug'16, IE and Safari still don't support that. – raina77ow Aug 05 '16 at 21:13
8

You can send binary data via ajax with xhr2, you can send the data as a typed array or a blob.

(function ($) {
   var data = new Uint32Array(1);
   data[0] = 0xFD008001; 
   $.ajax({
      url: '<IP of Address>',
      type: 'POST',
      contentType: false,
      processData: false,
      //data:'253,0,128,1',
      data:data,

      crossDomain: true
   });
})(jQuery);

https://developer.mozilla.org/en-US/docs/Web/API/Uint32Array

Musa
  • 96,336
  • 17
  • 118
  • 137
1

You can convert your data with type of ArrayBuffer to a ArrayBufferView like this:

var fileContent = new DataView(<ArrayBuffer_data>);

With this you wont get a warning in the console when sending fileContent.

Jonny
  • 816
  • 10
  • 24
0

You could use atob() and btoa():

var data = new Uint32Array(1);
data[0] = 0xFD008001;
atob(data)

This converts your binary data into a base64 string that can be sent as text.

Ben L.
  • 786
  • 7
  • 15
Sohail Si
  • 2,750
  • 2
  • 22
  • 36