Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add X-Requested-With header #16

Closed
tkleinhakisa opened this issue Nov 26, 2012 · 40 comments
Closed

Add X-Requested-With header #16

tkleinhakisa opened this issue Nov 26, 2012 · 40 comments

Comments

@tkleinhakisa
Copy link

Hi,

I think it should be nice to have hinclude send and "X-Requested-With" header with the value "XMLHttpRequest"

Most js framework send this header with ajax requests and the server side framework i know (including symfony2 which has support for hinclude) use this header to help detect ajax requests

Thanks
Tom

@mnot
Copy link
Owner

mnot commented Nov 29, 2012

What is it actually useful for, though?

@tkleinhakisa
Copy link
Author

Hi

It is usefull for detecting ajax request on the server side
It is used by framework like symfony2 or zf2

if i want some server-side code to be executed only in ajax request there is currently no way to detect it using hinclude

Thanks
Tom

@Zeichen32
Copy link

+1

@mnot
Copy link
Owner

mnot commented Mar 29, 2013

What I'm asking for is the use case for this header - why do you need to know that it's an Ajax request on the server side?

Changing content based upon request headers is inviting problems; e.g.,
http://steveluscher.com/archives/ajax-requests-x-requested-with-headers-and-unexpected-cache-contents

@mnot
Copy link
Owner

mnot commented Mar 29, 2013

Oh, and X-R-W also causes problems with CORS; e.g.,
angular/angular.js#1454

@hakisa-jerome
Copy link

http://steveluscher.com/archives/ajax-requests-x-requested-with-headers-and-unexpected-cache-contents this one was just a particular bug that had to be handled by the developer.

I still think that checking if the request was made through Ajax or not to render a response in the good format is a good use case. Anyway other use cases may exist.

If you read the bug related to angular/angular.js#1454 (angular/angular.js#1004) you'll see that simply removing X-Requested-With is not the best solution. I think removing it only if it is a cross domain request as in jQuery is a better solution.

Maybe there's just a condition missing in my pull request...

@mnot
Copy link
Owner

mnot commented Apr 6, 2013

Sorry, I'm not convinced. What does "good format" mean here? Are you saying that you just want to change to JSON or XML (for example), or that you want to fundamentally return a different response?

Please give a concrete use case.

@hakisa-jerome
Copy link

I don't want to discuss anymore, you'll never be convinced and there's no problem with that, I'll just stick with my own solution.

@tkleinhakisa
Copy link
Author

Simple use case:

I have an action to edit an entity.
In normal GET context (not ajax) i want my action to render a full page, including my layout
In ajax GET context i want to only render the form so i can put it in a modalbox

even rails use this header to check for ajax request (http://apidock.com/rails/ActionController/Request/xml_http_request%3Fhttp://apidock.com/rails/ActionController/Request/xml_http_request%3F) ... don't you think that if all great webframework use it, it is for a reason ?

@kingcrunch
Copy link

Another example: Login.
When I call the url directly, it should show the whole login page. When I call it via ajax, it should only return the login form.

@gnat42
Copy link

gnat42 commented Jun 3, 2013

Yeah, I usually use it for this same use case. One URL that returns just the form without the full layout via ajax but full layout without...

@J7mbo
Copy link

J7mbo commented Jun 7, 2013

Symfony2 has an isXmlHttpRequest method as a major, often used method of the Request class.

As this method, and other server side frameworks use the X-Request-With header to check for a valid XmlHttpRequest, +1. This would be very useful!

@KeKs0r
Copy link

KeKs0r commented Jul 18, 2013

+1, I really need this one as well, because on ajax calls I only render the main content, on regular calls I render content and layout. Currently Hinclude renders my whole layout within some modals.

@mikemeier
Copy link

+1 - cant be that hard to understand why its necessary, isnt it?

@mnot
Copy link
Owner

mnot commented Aug 29, 2013

+1'ing doesn't add any information. Saying "lots of other people do it" doesn't help either.

No one has explained why their application needs to have the same URL for Ajax vs. non-Ajax requests; the only motivation I can see is that developers want to do it that way because they assume it should work, without considering the impacts of giving fundamentally different content the same URL.

I.e., adding this header is likely to cause problems for most people who use it because they don't consider how it works with other parts of the Web. This is an anti-pattern, and other frameworks that do it should really stop.

Closing this issue; if someone can show how this is wrong, I'll reopen.

@mnot mnot closed this as completed Aug 29, 2013
@bluesmoon
Copy link

There is no genuine use case for the X-R-W header. All existing implementations did it that way because they either thought it was the right way or wanted to be clever. Way back when (ca. 2004/2005), we used to tell the server what we wanted using one of three ways:

  • A different file extension, eg: index.html, index.xml, index.json
  • A query string parameter, eg: type=xml or type=json or even type=jsonp&callback=foo, with the default being html
  • An Accept header, ie, Accept: text/html v/s Accept: application/xml

These methods were proposed by many of the best practitioners of the time, and they're still the best ways to do it. Your app should not be relying on non-standard headers to decide what to do when methods of content negotiation already exist. Just because a lot of people implemented things badly doesn't make it right.

@jvhellemond
Copy link

Don't we have the Accept request header to do this?

"The Accept request-header field can be used to specify certain media types which are acceptable for the response."
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Not sure if this header can be set using XHR, but I always use it just for this scenario (full HTML for "humans", same content but JSON for XHR).

@kingcrunch
Copy link

@bluesmoon @jvhellemond So you can explain, which is the correct media type for a partial HTML? 😉

@gingters
Copy link

Well said, bluesmoon.

The best argument against this 'unfeature' / anti-pattern is: Usage of this application through mobile networks. At least here in germany, I suppose in other countries too, mobile network carriers use a lot of extremely aggressive caching to keep data transfer rates low.

If a web server response for a request to /Login is initially done none-ajax, the result (in the given example the Full html) will be cached by the carrier. When the next request (ajax-request from another client) goes to /Login, the carrier most probably won't look at the X-Reqested-By header, and deliver the full cached HTML response. That fucks up any application relying on this.

Working around these issues usually involve setting cache-headers to prevent caching in most cases and makes the application slow (you wanted also to prevent 'slow' by using ajax in the first place, didn't you?).

There is no good reason to use X-R-W that would not complicate things and won't introduce additional potential error-vectors. Imho.

@vrolijken
Copy link

-1 : @kingcrunch Accept: text/part+html

@kingcrunch
Copy link

@vrolijken Can you give me a resource, where this type is defined? Because if you argue that X-Requested-With is not a standard header, you shouldn't propose another non-standard als alternative 😕

Beside: I like @gingters answer :) It makes sense

@dominikzogg
Copy link

+1

@mstade
Copy link

mstade commented Aug 29, 2013

-1

Add a <link> to a different URL that provides the resource you want, and use that for the XHR. That way, when you retrieve the full page your application can discover where to find the resource, and you get a hypermedia driven solution. You can then also switch between solutions by serving up different representations based on whatever negotiation criteria you want. There's no need to invent new headers for what can already be done, particularly when the effort involved is more or less he same.

@sebs
Copy link

sebs commented Aug 29, 2013

I am not certain, but I think preventing caching can be done with HTTP headers that are in the RFC 2616, Section 14
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

All those "aggressive" caching mechanisms (and CDN's for that matter) rely on usage of those RFCs (and maybe some violations). Please check in that RFC before adding to existing mechanisms. Those were invented for a reason, they are pretty old and Ajax is using HTTP as transport. So the RFC applies. If you mobile carrier brakes HTTP RFCs, write a mail to the support and tell them to RTFM the RFC and offer proper internets.

@pixeltrix
Copy link

In Rails we use it to work around broken Accept: headers sent by browsers. If */* is present without the X-Requested-With header we'll send HTML by default, whereas if the header is present we'll return what the Accept: header has asked for. jQuery includes */* by default so without the header you'd have to override the accept header on every ajax request otherwise you'd get HTML back when you asked for application/json

Also if there's no Accept: header and X-Requested-With is present we'll render the JS template by default instead of the HTML. The relevant code is in this module: https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/mime_negotiation.rb

I believe the general recommendation by Rails core is that Accept: is broken and it's better to use explicit formats in your urls - if you look at the code linked above you'll see that we give precedence to the :format parameter over the accept header.

@rudiedirkx
Copy link

I don't know what hinclude is, but still, here's my 2c:

My app uses XRW for its response. If a request was made with Ajax, the response is only the content part, otherwise it's the full page (including menu, header, CSS etc etc). So the server knows to do less, because only the content part (a table or a list) is relevant AND the client will receive only the relevant part. The URLs are always the same though, e.g.: /reservations/2013-01-01. The Accept header in this case is useless, because it's always text/html. The accept header is useless in other cases too, because a CSV export is just a link and the client can't set a header for that, so you'll need to change the URL or add a query param: /reservations/2013-01-01/export.csv or /reservations/2013-01-01?csv, but now I might be digressing.

@joe-mojo
Copy link

All people here not using Accept header or a different url for partial content don't make RESTful apps and/or API. They are wrong. Like all those people that wrote broken markup/js because 95% of people were using IE6.

Please don't hurt the web, respect standards... and be RESTful.

PS : Not only the X-Requested-With header is "borken" by design, but is now recommended not creating X-* headers. Just sayin'

@pixeltrix
Copy link

All people here not using Accept header or a different url for partial content don't make RESTful apps and/or API. They are wrong. Like all those people that wrote broken markup/js because 95% of people were using IE6.

Wow, it must be great to have clients that don't care that their site doesn't work in large proportion of browsers - my clients don't really care whether I respect the standards or not. :trollface:

Please don't hurt the web, respect standards... and be RESTful.

The X-Requested-With header at least allows Rails to use Accept: for clients that 'respect' the standards - without it we'd have to turn off content negotiation everywhere and rely on urls with embedded formats.

PS : Not only the X-Requested-With header is "borken" by design, but is now recommended not creating X-* headers. Just sayin'

I believe the advice was to not create new headers prefixed with X since there was no point - a bit like browser vendors supporting other browsers' CSS prefixes, making them redundant. Since X-Requested-With was added 8 years ago I think we're good to keep using it 😄

@mstade
Copy link

mstade commented Aug 30, 2013

The X-Requested-With header at least allows Rails to use Accept: for clients that 'respect' the standards - without it we'd have to turn off content negotiation everywhere and rely on urls with embedded formats.

If Rails recommends the use of a different URL rather than headers, then why not just run with that? It's a little silly to introduce a new, non-standard header in order to hack in support for one that's already available, documented and should do what it says on the tin. If (bad) clients don't respect headers, what's to say X-R-W is in any better position in the future (which, arguably, should be more important than the present.) The unfortunate reality of having to deal with shitty clients doesn't provide justification when there is a well supported solution at hand: URLs. They are cheap, well supported and actually solves the problem. It might not be fancy and shiny, but at least it doesn't smell.

@pixeltrix
Copy link

It's a little silly to introduce a new, non-standard header

Who said it was new? It was added to Rails version 0.12 - it predates the adding of REST support to Rails.

The unfortunate reality of having to deal with shitty clients doesn't provide justification when there is a well supported solution at hand: URLs. They are cheap, well supported and actually solves the problem. It might not be fancy and shiny, but at least it doesn't smell.

URLs are the preferred way and take precedence over the Accept header but we still support the header - we're opinionated, not dogmatic 😄

It's up to @mnot whether he wants to add the header or not - I'm just providing some context on it's history and usage

@mstade
Copy link

mstade commented Sep 6, 2013

Who said it was new? It was added to Rails version 0.12 - it predates the adding of REST support to Rails.

Fair enough; I obviously used the word "new" too freely, my apologies. The salient point being that using standard and better supported mechanisms is preferable to introducing new ones. (Oops, I guess I did it again.)

we're opinionated, not dogmatic 😄

:)

@peter-gribanov
Copy link
Contributor

+1 I do not think it's right to give a different content (different layout) for a single URL. But we need to be able to distinguish AJAX requests and full requests.
For example, i do not want to content loaded via AJAX was available in full request. For example, without this restriction, you can freely embed content on other sites. Of course, this restriction is easy to get around, but that is no reason not to use it.

@bluesmoon
Copy link

@peter-gribanov it causes performance problems. Do not do it. Use the standard Accept header instead. See https://www.soasta.com/blog/options-web-performance-with-single-page-applications/ for details.

@peter-gribanov
Copy link
Contributor

@bluesmoon currently headlines X-Requested-With or Accept are not forcibly sent. When you send the AJAX request, Accept header is set to */*. Do you really think it is right to identify the AJAX request?

@bluesmoon
Copy link

Accept is the right header. You should not be "identifying AJAX" (ie, transport method), you should be "identifying required content".

@peter-gribanov
Copy link
Contributor

@bluesmoon no. In this case, the content will be same in both cases, but the call context differs.
Identify call context can only be by headers X-Requested-With and Referer. Header Accept indicates that we expect to receive and in both cases it will be a text/html because the library can load only HTML code.

@bluesmoon
Copy link

If the content is the same then why does it matter what the requesting context is? The whole point of using HTTP is that the requesting context is irrelevant.

@peter-gribanov
Copy link
Contributor

@bluesmoon yes, that's right. But i'm interested in the ability to block access to content that is not supposed to show in full request.

@bluesmoon
Copy link

Then you should use a query string parameter or different URL to distinguish. Your client & server may understand custom HTTP headers, but intermediate proxies will not, which means they might respond with cached copies based on the URL and some of the basic content headers. I've seen intermediate proxies also ignore Cache-control headers (and a smaller number even ignore query strings), so a different URL is really the only way to handle this particular case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests