Partial XHR response reading for binary data, possible? - javascript

I am currently researching the possibility of reading partial XHR responses with binary data. Our current approach is based on the 'responseText' property and base64 encoding. Clearly, this is far from optimal.
How could we read partial Blob/ArrayBuffer responses using XHR? When I try in Chrome, the entire ArrayBuffer/Blob is made available when readyState = 4, but not before that.
To summarize, it seems to me that:
Reading XHR's responseText property: Responses can be read before readyState = 4, and we can stream base64 encoded binary data back to the client
Reading XHR's response property with responseType = 'arraybuffer': No partial response reading, but the entire buffer is made available when readyState = 4
Am I missing something here? What approach could we take to read partial binary responses?

Keep your eyes on the fetch API, currently supported by Firefox and Chrome.

There is a way, though it's not standard yet. Firefox allows you to set responseType on XHR to "moz-blob", "moz-chunked-text" or "moz-chunked-arraybuffer", depending on which one works for you. Then, when you listen for the progress event, you will be able to access partial data as it comes in. MDN has more info on that here and here.
Chrome will support the Streams API, but it's not ready yet. Firefox may also eventually support it. I read somewhere that IE does already, though I can't seem to find any official documentation to confirm that.

The best API to use as an XHR replacement is fetch with readableStream.
This is explained here:
https://developers.google.com/web/fundamentals/primers/async-functions#example_streaming_a_response
Chrome already supports it. Firefox implements it but it must be activated manually for the moment (it will be activated by default in a future version).
While waiting for this activation, Firefox implements the XHR with the non-standard response type moz-chunked-arraybuffer
The library https://www.npmjs.com/package/fetch-readablestream proposes an API that implements these two methods. It uses https://www.npmjs.com/package/web-streams-polyfill.

Related

My DELETE method doesn't work from a Submit Form [duplicate]

I've seen a couple questions around here like How to debug RESTful services, which mentions:
Unfortunately that same browser won't allow me to test HTTP PUT, DELETE, and to a certain degree even HTTP POST.
I've also heard that browsers support only GET and POST, from some other sources like:
http://www.packetizer.com/ws/rest.html
http://www.mail-archive.com/jmeter-user#jakarta.apache.org/msg13518.html
http://www.xml.com/cs/user/view/cs_msg/1098
However, a few quick tests in Firefox show that sending PUT and DELETE requests works as expected -- the XMLHttpRequest completes successfully, and the request shows up in the server logs with the right method. Is there some aspect to this I'm missing, such as cross-browser compatibility or non-obvious limitations?
No. The HTML 5 spec mentions:
The method and formmethod content attributes are enumerated attributes
with the following keywords and states:
The keyword get, mapping to the state GET, indicating the HTTP GET
method. The GET method should only request and retrieve data and
should have no other effect.
The keyword post, mapping to the state
POST, indicating the HTTP POST method. The POST method requests that
the server accept the submitted form's data to be processed, which may
result in an item being added to a database, the creation of a new web
page resource, the updating of the existing page, or all of the
mentioned outcomes.
The keyword dialog, mapping to the state dialog, indicating that
submitting the form is intended to close the dialog box in which the
form finds itself, if any, and otherwise not submit.
The invalid value default for these attributes is the GET state
I.e. HTML forms only support GET and POST as HTTP request methods. A workaround for this is to tunnel other methods through POST by using a hidden form field which is read by the server and the request dispatched accordingly.
However, GET, POST, PUT and DELETE are supported by the implementations of XMLHttpRequest (i.e. AJAX calls) in all the major web browsers (IE, Firefox, Safari, Chrome, Opera).
HTML forms support GET and POST. (HTML5 at one point added PUT/DELETE, but those were dropped.)
XMLHttpRequest supports every method, including CHICKEN, though some method names are matched against case-insensitively (methods are case-sensitive per HTTP) and some method names are not supported at all for security reasons (e.g. CONNECT).
Fetch API also supports any method except for CONNECT, TRACE, and TRACK, which are forbidden for security reasons.
Browsers are slowly converging on the rules specified by XMLHttpRequest, but as the other comment pointed out there are still some differences.
XMLHttpRequest is a standard object in the JavaScript Object model.
According to Wikipedia, XMLHttpRequest first appeared in Internet Explorer 5 as an ActiveX object, but has since been made into a standard and has been included for use in JavaScript in the Mozilla family since 1.0, Apple Safari 1.2, Opera 7.60-p1, and IE 7.0.
The open() method on the object takes the HTTP Method as an argument - and is specified as taking any valid HTTP method (see the item number 5 of the link) - including GET, POST, HEAD, PUT and DELETE, as specified by RFC 2616.
As a side note IE 7–8 only permit the following HTTP methods: "GET", "POST", "HEAD", "PUT", "DELETE", "MOVE", "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "LOCK", "UNLOCK", and "OPTIONS".
_method hidden field workaround
Used in Rails and could be adapted to any framework:
add a hidden _method parameter to any form that is not GET or POST:
<input type="hidden" name="_method" value="DELETE">
This can be done automatically in frameworks through the HTML creation helper method (e.g. Rails form_tag)
fix the actual form method to POST (<form method="post")
processes _method on the server and do exactly as if that method had been sent instead of the actual POST
Rationale / history of why it is not possible: https://softwareengineering.stackexchange.com/questions/114156/why-there-are-no-put-and-delete-methods-in-html-forms
I believe those comments refer specifically to the browsers, i.e., clicking links and submitting forms, not XMLHttpRequest. XMLHttpRequest is just a custom client that you wrote in JavaScript that uses the browser as a runtime.
UPDATE: To clarify, I did not mean (though I did write) that you wrote XMLHttpRequest; I meant that you wrote the code that uses XMLHttpRequest. The browsers do not natively support XMLHttpRequest. XMLHttpRequest comes from the JavaScript runtime, which may be hosted by a browser, although it isn't required to be (see Rhino). That's why people say browsers don't support PUT and DELETE—because it's actually JavaScript that is supporting them.
YES, PUT, DELETE, HEAD etc HTTP methods are available in all modern browsers.
To be compliant with XMLHttpRequest Level 2 browsers must support these methods. To check which browsers support XMLHttpRequest Level 2 I recommend CanIUse:
http://caniuse.com/#feat=xhr2
Only Opera Mini is lacking support atm (juli '15), but Opera Mini lacks support for everything. :)
Just to add - Safari 2 and earlier definitely didn't support PUT and DELETE. I get the impression 3 did, but I don't have it around to test anymore. Safari 4 definitely does support PUT and DELETE.

Using GWT, how to load an image and access image attributes & http status codes

Using GWT I am loading images from a server I do not control. Currently, I use GWT new Image( url) and then use ImageHandlers and ErrorHandlers to catch what happened and put the images in my buffer and the DOM. Then I make the images visible sequently to animate the process. But now I need a bit more, I need to know the error code, e.g.304 that the server returned for the image and also I need to get at the header response attribute, 'Last-modified'. For 304, I know I need to resubmit the request later when the server will have created a new version ( with exactly the same url ) which I think I can manage, but it will then have a new 'Last-modified' and I need to know that DateTime.
By using new Image(url), I am letting the browser do the loading, but I don't know how to get at the details of the load.
Q1:Is there a way to pull more info from an image?
GWT Image just seeems to wrap a JS object. I look in Firefox Console-Network, but don't see much detail there either. Is Last-modified and error code forgotten by the time it gets (or doesn't) in the DOM tree.
If the answer to Q1 is no the information is gone or inaccessible, ..
Q2: Do I need to stop using the browser to fetch images and do it with an XmlHttpRequest and then presumably I have access to the response codes and the header attributes. SOP is not an issue. But how then do I get from say the Response OutputStream to an Image? Do I have to Base64 encode it or is there a better way? Will one of the other non-url constructors for image help, say Image(Element) or Image(ImageResource). Then the issue becomes how to make a response stream into a Element or ImageResource?
Note: This other question 'How to print error message of why image failed to load?' is related, but doesn't get to an answer.
Getting Error codes, and getting the response as a stream must be done with an HTTP client (GWT has the built in RequestBuilder). You can also try to get the error code with native JS, using the method described here.

Caching GET response in Javascript Vanilla

I've noticed that Firefox does not cache GET requests automatically. Following the code I use:
var ajax = new XMLHttpRequest();
ajax.open("GET","page.php?val=" + val,true);
ajax.send();
With jquery is possible to give cache: true;, how can I save in the cache with Vanilla Javascript (client side)? Is also possible to decide for how long? Can you give me an example of code? Thank you in advance!
Web caching is largely controlled by the headers sent from the Server (Expires:, etc.). Browsers sometimes "cheat" and don't really cache even though the headers would allow them to ...probably because the user had used their UI to turn off caching, for example by setting the cache size to zero. But browsers that "cheat" the other direction, caching anyway even though the headers don't allow it, are (for good reason) extremely uncommon.
If caching is not happening for you, it's a function of the file and the server (or perhaps the browser configuration), not of any browser type or version. (To say the same thing a different way, your Firefox would cache just fine if the Server sent the needed headers.) The headers are controlled a variety of ways by different servers and different providers. For the Apache server, the nitty-gritty may be in a ".htaccess" file, pre-written templates of which are often available.
To a first approximation, with HTML4, you simply cannot control web caching from the client side, no matter what tool you use and no matter what your program does. A generic exception is provided by the new "online application cache" or "appcache" in HTML5 ...but with other restrictions, for example those about "one per site" and "same origin".
You can cache responses using a simple hash, something like:
var cache = {};
function getData(variable) {
if (cache[variable]) {
return cache[variable];
}
// previous ajax code to get the data...
// in the response handler, do:
cache[variable] = data;
}
That's a naive implementation of a caching mechanism: only works for the lifetime of the page (i.e., until the page is refreshed or navigated away from), doesn't have any expiration mechanism, and other shortcomings I'm sure. For instance, you could use localStorage to get around the refresh issue.
But hey, I'm not getting paid to write this :).

XMLHttpRequest gives Invalid state when using Last.fm API

I'm trying to integrate scrobble support into Ubuntu Touch's music app, but I have some difficulty since I can't seem to get the session key working.
In request() I get "Error: Invalid state" on row 53. It seems like last.fms API doesnt answer correctly, nor has the correct state, but I'm new to XMLHttpRequest, so I'm not sure what's the matter.
Code: http://pastebin.com/Aa6DVUA1
You're executing encodeURIComponent with the complete URL instead of the individual query arguments, thus resulting in something like https%3A%2F%2Fws.audioscrobbler.com%2F2.0%2F%3Fmethod%3Dartist.getsimilar%26artist%3DKiss... which is clearly not a valid URL. For an example see here.
Secondly, your usage of XMLHttpRequest is wrong, XHR operates asynchronously but you never define a callback function for your request. Querying xhr.readyState and xhr.status immediately after invoking send() will be executed before the request actually finishes. See here for how to use XHR.
PS: Why not use one of the existing API wrappers for JavaScript, i.e. http://lastfm.felixbruns.de/javascript-last.fm-api/ or at least jQuery to handle the XHR?
PPS: Your authentication request will not work, as you are required to submit the arguments in the post body as opposed to the query string, see this forum post for more information.

Reading contents of an iframe with wikipedia source? [duplicate]

I am trying to implement a simple request to Wikipedia's API using AJAX (XMLHttpRequest). If I type the url in the address bar of Firefox, I get a neat XML, no sweat there. Yet, calling the exact same url with:
// this is my XMLHttpRequest object
httpObjectMain.open("GET", "http://en.wikipedia.org/w/api.php?action=query&format=xml&prop=langlinks&lllimit=500&titles=kaas", true);
httpObjectMain.send(null);
returns an empty response. According to FireBug, I get a 200 OK response, but the content is just empty.
I suspect I might be missing something on the header of the GET http request.
Help! (and thanks!)
The Wikipedia API does support JSONP.
Your query string'll become something like this:
http://en.wikipedia.org/w/api.php?action=query&format=json&callback=test&prop=langlinks&lllimit=500&titles=kaas
But you'll have to build the jsonp handler (or you can use your favorite library to do it), switch to json output format from the xml you choose and create the callback function to parse the result and do the stuff you need on the page.
The browser will not allow you to send an XHR to another domain other than the one the page is on. This is for security purposes.
One way around this that I have seen is to setup a proxy on the domain the page is hosted on that will pass requests through to the actual api server. See http://ajaxpatterns.org/Cross-Domain_Proxy

Categories