views:

16733

answers:

12

Having trouble with what I thought was a relatively simple jQuery plugin...

The plugin should fetch data from a php script via ajax to add options to a <select>. The ajax request is pretty generic:

$.ajax({
        url:o.url,
    type: 'post',
    contentType:"application/x-www-form-urlencoded",
    data: '{"method":"getStates", "program":"EXPLORE"}',
    success: function(data, status) {
        console.log("Success!!");
        console.log(data);
        console.log(status);
        },
    error: function(xhr, desc, err) {
        console.log(xhr);
        console.log("Desc: " + desc + "\nErr:" + err);
        }
    });

This seems to work fine in Safari. In Firefox 3.5, the REQUEST_TYPE on the server is always 'OPTIONS', and the $_POST data does not appear. Apache logs the request as type 'OPTIONS':

::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46

Why would this ajax call work in Safari, but not Firefox, and how do I fix it for Firefox?

Thanks!

    Response Headers
Date: Wed, 08 Jul 2009 21:22:17 GMT

Server:Apache/2.0.59 (Unix) PHP/5.2.6 DAV/2

X-Powered-By: PHP/5.2.6

Content-Length  46

Keep-Alive  timeout=15, max=100

Connection  Keep-Alive

Content-Type    text/html

Request Headers
Host    orderform:8888

User-Agent  Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5

Accept  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language en-us,en;q=0.5

Accept-Encoding gzip,deflate

Accept-Charset  ISO-8859-1,utf-8;q=0.7,*;q=0.7

Keep-Alive  300

Connection  keep-alive

Origin  http://ux.inetu.act.org

Access-Control-Request-Method   POST

Access-Control-Request-Headers  x-requested-with

Here's a picture of the Firebug output: http://www.flickr.com/photos/fitzgeraldsteele/3701700103/

+1  A: 

I seems that if o.url = 'index.php' and this file exists is ok and returning a success message in the console. It returns an error if I use url:'http://www.google.com'.

If doing a post request why not using directly the $.post method:

$.post("test.php", { func: "getNameAndTime" },
    function(data){
        alert(data.name); // John
        console.log(data.time); //  2pm
    }, "json");

It is so much simpler.

Elzo Valugi
Got the same thing with this...thought I should use $.ajax() so I could at least get some debug info on the error condition..
fitzgeraldsteele
A: 

Can you try this without

contentType:application/x-www-form-urlencoded

Malcolm Frexner
Same result, I'm afraid.
fitzgeraldsteele
+37  A: 

The reason for the error is the same origin policy. It only allows you to do XMLHTTPRequests to your own domain. See if you can use JSON instead:

$.getJSON( 'http://&lt;url&gt;/api.php?callback=?', function ( data ) { alert ( data ); } );
world_eggplant
Ahh...that seems to be it. when I put everything on the same server, I'm getting much better results. Thanks!
fitzgeraldsteele
thanks. had the same problem, using the same domain (subdomains also create problems) worked for me.
Agos
Note: See this http://docs.jquery.com/Release:jQuery_1.2/Ajax#Cross-Domain_getJSON_.28using_JSONP.29 for info on using JSONP. You will need the additional "=?" in your query string to trigger JSONP
phirschybar
why is firefox the only browser to do this? I want a post not a get.
Maslow
$.getScript should be possible cross-domain, see http://docs.jquery.com/Release:jQuery_1.2/Ajax#Cross-Domain_getScript (but it is not for me in FF 3.6)
blueyed
+1  A: 

Try adding the option:

dataType: "json"

ScottE
+1  A: 

I was looking through source 1.3.2, when using JSONP, the request is made by building a SCRIPT element dynamically, which gets past the browsers Same-domain policy. Naturally, you can't make a POST request using a SCRIPT element, the browser would fetch the result using GET.

As you are requesting a JSONP call, the SCRIPT element is not generated, because it only does this when the Type of AJAX call is set to GET.

http://dev.jquery.com/ticket/4690

Slava0008
+3  A: 

This mozilla developer center article describes various cross-domain request scenarios. The article seems to indicate that a POST request with content type of 'application/x-www-form-urlencoded' should be sent as a 'simple request' (with no 'preflight' OPTIONS request). I found , however, that Firefox sent the OPTIONS request, even though my POST was sent with that content type.

I was able to make this work by creating an options request handler on the server, that set the 'Access-Control-Allow-Origin' response header to '*'. You can be more restrictive by setting it to something specific, like 'http://someurl.com'. Also, I have read that, supposedly, you can specify a comma-separated list of multiple origins, but I couldn't get this to work.

Once Firefox receives the response to the OPTIONS request with an acceptable 'Access-Control-Allow-Origin' value, it sends the POST request.

A: 

I had a similar problem with trying to use the Facebook API.

The only contentType which didn't send the Preflighted request seemed to be just text/plain... not the rest of the parameters mentioned at mozilla https://developer.mozilla.org/en/http_access_control

  • Why is this the only browser which does this?
  • Why doesn't Facebook know and accept the preflight request?

FYI: The aforementioned Moz doc suggests X-Lori headers should trigger a Preflighted request ... it doesn't.

Drew
A: 

Hi

Has anyone got this to work in Firefox? For my use case, pages on one server make ajax calls to another server

Any help in solving this would be greatly appreciated

Regards Damien

Damo
This is what the comment system is for. Note that above the textbox into which you entered this, it said "Your Answer"; unfortunately what you posted is in fact not your answer.
Domenic
@Damo, why not just use the "delete" link underneath this post? Thanks!
Arjan
+1  A: 

Another possibility to circumvent the problem is to use a proxy script. That method is described for example here: http://developer.yahoo.com/javascript/howto-proxy.html

Niehztog
+1  A: 

I used the following code on Django side to interpret the OPTIONS request and to set the required Access-Control headers. After this my cross domain requests from Firefox started working. As said before, the browser first sends the OPTIONS request and then immediately after that the POST/GET

def send_data(request):
    if request.method == "OPTIONS": 
        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        response['Access-Control-Max-Age'] = 1000
        response['Access-Control-Allow-Headers'] = '*'
        return response
    if request.method == "POST":
        # ... 

Edit: it seems to be that at least in some cases you also need to add the same Access-Control headers to the actual response. This can be a little bit confusing, since the request seems to succeed, but Firefox does not pass the contents of the response to the Javascript.

Juha Palomäki
Your edit about the actual POST/GET response is a bit scary; if anyone can confirm that, then please let us know here!
Arjan
I don't know if it is as bug or a feature, but seems to be that somebody else has noticed it as well. See for example http://kodemaniak.de/?p=62 and search for "empty response body"
Juha Palomäki
+1  A: 

Check if your form's action URL includes the www part of the domain, while the original page you have opened is viewed without www.

Canonical Urls..

I struggled for hours before stumbling upon this article and found the hint of Cross Domain.

Bijay Rungta
A: 

This PHP at the top of the responding script seems to work. (With Firefox 3.6.11. I have not yet done a lot of testing.)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
if(array_key_exists('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', $_SERVER)) {
    header('Access-Control-Allow-Headers: '
           . $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
} else {
    header('Access-Control-Allow-Headers: *');
}

if("OPTIONS" == $_SERVER['REQUEST_METHOD']) {
    exit(0);
}
Chad Clark
This might be a matter of taste, but *always* sending those response headers (also for `GET`, `POST`, ...) is a bit too much to my liking. (And, I wonder if always sending those complies with the specs?)
Arjan