Is there a way of requesting a specific part of a web resource (such as the first 100 bytes) asynchronously from JavaScript?
I'd assumed this could be done through XmlHttpRequest by setting its Range header. However, if the server applies content-encoding (which most do by default), the byte range would apply to the encoded data, not the original. Per HTTP/1.1:
When an entity-body is included with a message, the data type of that
body is determined via the header fields Content-Type and Content-
Encoding. These define a two-layer, ordered encoding model:
entity-body := Content-Encoding( Content-Type( data ) )
Byte range specifications in HTTP apply to the sequence of bytes in
the entity-body […].
This renders the retrieved content useless, since it cannot be decoded without retrieving (and concatenating) the rest of the encoded resource.
It is apparently not possible to disable content-encoding from the client-side, since XMLHttpRequest prohibits the Accept-Encoding from being changed.
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () { /* ... */ };
xhr.open("GET", url, true);
xhr.setRequestHeader("Range", "bytes=0-99");
xhr.setRequestHeader("Accept-Encoding", "identity"); // not allowed
xhr.send();
Is there another way of achieving this (assuming content-encoding cannot be disabled on the server)?
You could try using old style techniques of simulating ajax behaviour like loading hidden iframe with all headers that you mention(and probably the encoding header will be allowed) and getting data from such hidden iframe. Here is example for uploading multipart data using hidden iframe: example. You could change it for your needs. Maybe it will help.
Related
I used to search and read posts related to this topic but now I am a little bit confused again.
As before, I read many posts but still didn't see any post clearly clarifying how these different content type would affect or maniuplate the client's data, when the client is sending data to server.
So here's my understanding (assume it's a POST method):
There are 2 content types are special and treated differently from the rest.
application/x-www-form-urlencoded and multipart/form-data.
with application/x-www-form-urlencoded, the client's data is encoded (changed) in some ways.
with multipart/form-data, the client will use something called boundary as a delimiter. As a result, the client can send many stuffs all together in a single request with some boundary string inserted as delimiters.
And for all the other content types specified by the client (xmlhttp.setRequestHeader) , e.g. application/json, application/pdf, application/image, application/octet-stream blablabla, the client won't change anything but just put the raw (binary) data in the http request body and send it to the server. The server can retrieve the raw data from the http request body and do whatever it wants.
Is my understanding/classfication correct?
By saying "client", I mean browser mostly.
By saying "server", I mean the server framework or applicaiton.
Because if I understand correctly, the web server e.g. Nginx or Apache won't do anything to the data. They just pass the data to the server-side application connected to them.
There are 2 content types are special and treated differently from the rest.
No. Those 2 content types (and text/plain which is pointless and you should never use) are supported by HTML forms.
with application/x-www-form-urlencoded, the client's data is encoded (changed) in some ways.
With a regular HTML form, all the encodings change the data in some way (even if it is text/plains "Make everything be name=value and shove a new line between each item).
with multipart/form-data, the client will use something called boundary as a delimiter.
Yes. text/plain uses a new line. application/x-www-form-urlencoded uses a &. Everything has a delimiter. (You just can't tell the delimiter apart of a new line in the data in text/plain which is what makes it useless).
As a result, the client can send many stuffs all together in a single request with some boundary string inserted as delimiters.
The client can send many things with any of those three encodings.
The different is that multipart supports files.
Multipart lets you put headers before the data for each part, so you can include things like filenames and content-types which are almost essential for supporting files.
And for all the other content types specified by the client (xmlhttp.setRequestHeader) , e.g. application/json, application/pdf, application/image, application/octet-stream blablabla, the client won't change anything but just put the raw (binary) data in the http request body and send it to the server.
Explicitly setting a content type has no effect on what the XMLHttpRequest object will do with what you pass to send().
If you pass a string, it will not encode that in any way (so you need to encode the data into the string yourself and set the right content-type header for the encoding you picked). If you pass a FormData object then it will encode it as multipart. etc.
Because if I understand correctly, the web server e.g. Nginx or Apache won't do anything to the data. They just pass the data to the server-side application connected to them.
That's generally the case, but somewhat oversimplified. e.g. There may be no distinction between the server and the server-side application if it is written using Express.js running on Node.js.
Summary
Forms always encode the data. The enctype attribute tells them which way to do it.
XMLHttpRequest and fetch may encode the data, but it depends on what kind of value you pass to them. If it is a string, you have to encode it and set the right Content-Type yourself.
i try to get text from a Http Get Request:
This is a small web service to correct texts.
http://193.196.7.26/cgi-bin/ColorError-line.pl?arg_childText=Ich%20gehe%20in%20die%20schule.&arg_errors=MOR_GrS;MOR_KS&arg_corrText=Ich%20gehe%20in%20die%20Schule.
When i call the service with a browser (f.e. Chrome) i see the corrected text.
Now i try this in Javascript:
var http2 = new XMLHttpRequest();
var url1 = "http://193.196.7.26/cgi-bin/ColorError-line.pl?arg_childText=Ich%20gehe%20in%20die%20schule.&arg_errors=MOR_GrS;MOR_KS&arg_corrText=Ich%20gehe%20in%20die%20Schule."
http2.open("GET", url, false);
http2.setRequestHeader("Content-type", "text/plain");
http2.send(null);
var temp = http2.responseText;
But responseText is empty. Any idea?
You must set the Access-Control-Allow-Origin header.
In .htaccess:
<Files "ColorError-line.pl">
Header set Access-Control-Allow-Origin *
</Files>
or print this header:
Access-Control-Allow-Origin: *
This will allow cross-domain access from any domain, not just yours. To only allow your domain only, you should set it to
Access-Control-Allow-Origin: http://yourdomain.com
without the slash in the end, but then you must remember to change it if your domain changes. This also applies to the .htaccess version.
Update: Also, you could create a proxy script to do it, as suggested here. However, I recommend that you filter the URL sent to the proxy, or someone could create lots of excess traffic to your site by downloading big files with it.
New to XMLHttpRequest, and here is some confusion for me:
Why must we set the content type when using the post method in a xmlhttprequest?
XHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
Isnt the default value application/x-www-form-urlencoded already?
Here is also one tool which help you for passing parameters via application/x-www-form-urlencoded. https://www.browserling.com/tools/url-encode. Also i suggest you to use Postman tool first to check the API response and then use Ajax call in JS
Why must we set the content type when using the post method in a xmlhttprequest?
XHR.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
HTTP/POST does not ask for that specific content-type when you do a HTTP/POST over AJAX (or for that matter via other means). It is up to you (and up to the server side program handling it). Read the second section for Why we must set it explicitly.
Very often, we serialise the form (percentile-encode it -- a=b&c=d format) and send it across to the server. This format is application/x-www-form-urlencoded. If you are sending an XML, you would use application/xml, for JSON you would use application/json and so on.
As for GET request, there's no body and hence we dont really need the content-type header.
Isnt the default value application/x-www-form-urlencoded already?
I tried skimming through here for the default content-type header. I couldn't find anything. However, when I tried doing a HTTP/POST AJAX request via chrome's console, I noticed that chrome's default is application/xml.
Just a piece of advice -- never rely on default behaviour except when its explicitly stated and/or is a part of the standard. Why not set the content type explicitly?
Ajax send request with encoding gzip (iis7) is not working below are the code for send request
can some one help me what is wrong in my code.
Thanks in advance
function sendRequest(url, callback, postData)
{
var req = createXMLHTTPObject();
if (!req) {
return;
}
var method = (postData) ? "POST" : "GET";
req.open(method, "xml/" + url, true);
req.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
if (postData) {
req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
req.setRequestHeader("Content-Encoding", "gzip");
}
req.onreadystatechange = function() {
}
req.send(postData);
}
Considering the security, browser does not allow you to override some headers including "Content-Encoding".
One way to transparently have the requests for your XMLHttpRequest highly compressed is to use HTTP/2 (e.g. serve your website via CloudFlare).
When using HTTP/2, then although the HTTP headers do not say Content-Encoding: gzip the underlying HTTP/2 protocol compresses everything.
It also compresses much better than gzip because:
it compresses headers
header compression uses a standard dictionary
I think data compression builds a dictionary over multiple messages (brotli - I haven't double-checked that though)
You can see if your server is using HTTP/2 by:
Open Chrome, and F12 to open developer tools
Click on the network tab
close the request inspector panel (has tabs Headers Preview Response Timing)
Right click on the Name header of the list of requests and tick Protocol
Navigate to your website and watch what protocol is used for all requests - in the protocol column you want to see h2 not http/1.1
I wouldn't recommend using JavaScript compression libraries because that causes slowdown and inefficiencies.
The problem doesn't seem to be related to header but to compression.
You don't seem to compress your postData.
If postData is already compressed, no need to try to manually set content-encoding.
If it is not, either let the browser negotiate the transfer encoding with the server (this is part of the protocol and done automatically, the server saying if it accepts it, but I think that's rarely the case) or (if you really really need to) encode it yourself. This SO question indicates a library to compress browserside : JavaScript implementation of Gzip
I stumbled on this command while learning AJAX. The guy who made the tutorial didn't explain this command, what do the parameters inside the command mean and what is it used for... Below is the code I used it in:
<script type="text/javascript">
function insert(){
if(window.XMLHttpRequest){
xmlhttp = new XMLHttpRequest();
}else{
xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
};
xmlhttp.onreadystatechange = function(){
if(xmlhttp.readyState == 4 && xmlhttp.status == 200){
document.getElementById('message').innerHTML = xmlhttp.responseText;
};
};
parameters = 'insert_text='+document.getElementById('insert_text').value;
xmlhttp.open('POST','ajax_posting_data.php',true);
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xmlhttp.send(parameters);
};
</script>
HTTP is a protocol. Part of that protocol is the concept of request headers. When an xhr happens, text is exchanged between the client and server. Request headers are part of the text that the client sends to the server.
This is a way to set the request headers. The arguments you see are
1) the header to set (in this case, Content-type)
2) the header value. (in this case, x-www-form-urlencoded)
See this for more info.
HTTP requests are messages passed from one computer system to another according to a set routine (a 'protocol' - here HyperText Transfer Protocol) in order to do things like send data, ask for data to be sent back, update data previously sent, etc.
A header is basically a piece of information about the data in the body of the HTTP request. Its purpose is to tell the machine receiving the request what type of data is enclosed in the body of the request, its formatting, the language used, if it's to set a cookie, the date, the host machine, etc.
More than one header can be put on a HTTP request and each header has a 'name' and a 'value' component. On web pages they look like
<meta name="........" content="............."/>
and you find them just below the top of the web page within the element.
To enable people to send HTTP requests from within a JavaScript function, we create a new XMLHttpRequest object, just as your code does so with
const xmlhttp = new XMLHttpRequest();
To this new empty object you intend to add data. Despite its name, XMLHttpRequest also allows sending data in a number of formats other than XML, e.g. HTML code, text, JSON, etc. In your example each data name will be separated from its value by an "=" character and each data/value pairing will be separated from the next pairing by an "&" character. This kind of formatting is known as URL encoding.
We have to tell the receiving computer how the data within the HTTP request body is encoded. There is a standard header to convey this and it is added to the request via the method setRequestHeader(..). This method uses 2 parameters, the header name and the header's value. All this operation is achieved in the line
xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
This setRequestHeader(..) method must be applied to the request after the request is characterized with the open(...) method but before the final request is sent off with the send(.) method.
The open(...) method defines: (1) the type of HTTP request, e.g. GET/POST/PUT etc; (2) the web page that contains the handling script for this request, e.g. some .php file or Node.js request endpoint that makes the appropriate query to the back end database; and (3) the nature of the request dynamics, e.g. asynchronous requests are assigned a value 'true', synchronous requests are assigned 'false'.
The send(.) method attaches the data to be sent within the body of the request, in your case the variable called 'parameters'.
On your broader question of which situations setRequestHeader(..) is used, I would say that it is used in most HTTP request situations. But some types of data added to the body of a HTTP request invoke a default setting for the 'Content-Type' header.
It is exactly what it says. It will set a "header" information for the next XMLHttpRequest.
A header is pretty much a key/value pair. It is used to transmit "meta" information to the target server for the ongoing request. In your particular instance, its used to tell the server which content type is used for this request.
It sets the Content-type HTTP header to contain url encoded data sent from a form.