ajax call from a page on a non-web2py server is not seen as ajax?

1,378 views
Skip to first unread message

simon

unread,
Aug 1, 2012, 4:42:15 PM8/1/12
to web...@googlegroups.com
I have a page served by a php application where a button makes an ajax call to a web2py controller. However when it arrives the request.ajax field is false and it then tries to redirect to the login page.

Is it possible to make an ajax call to a web2py server from a non-web2py page and send the response back to the callling page? Am I doing it wrong?

Richard Vézina

unread,
Aug 1, 2012, 4:51:47 PM8/1/12
to web...@googlegroups.com
Are you using web2py ajax or jQuery.ajax, I don't see why it shouldn't works with the later, but with the former I think it's not possible since it is a web2py subset of jQueyr ajax functions intent to work in a certain context within web2py.

On Wed, Aug 1, 2012 at 4:42 PM, simon <sim...@gmail.com> wrote:
I have a page served by a php application where a button makes an ajax call to a web2py controller. However when it arrives the request.ajax field is false and it then tries to redirect to the login page.

Is it possible to make an ajax call to a web2py server from a non-web2py page and send the response back to the callling page? Am I doing it wrong?

--
 
 
 

Anthony

unread,
Aug 1, 2012, 5:42:07 PM8/1/12
to web...@googlegroups.com
Yes, you can make Ajax calls to web2py and get a response back -- and that is independent of whether request.ajax is True. Here's the code used to set request.ajax:

                x_req_with = str(request.env.http_x_requested_with).lower()
                request
.ajax = x_req_with == 'xmlhttprequest'

So, web2py checks whether the request headers include "X-Requested-With: XMLHttpRequest". Perhaps for some reason your Ajax call is not setting that header. web2py will still respond to the request, but it won't set request.ajax to True unless that header is there. You could either make sure that header is set when the request is made, or add some other flag to the request that your application can use to determine the type of request (e.g., a GET or POST variable). See http://stackoverflow.com/questions/1885847/jquery-no-x-requested-with-xmlhttprequest-in-ajax-request-header.

Anthony

simon

unread,
Aug 1, 2012, 7:24:33 PM8/1/12
to web...@googlegroups.com
I am making the call using jquery. You are correct that the X-Requested header is not included automatically and without it the request shows  in chrome as a GET with response 303 redirect. If I explicitly add the X-Requested header then it shows as an "OPTIONS" request and instead of the headers it shows Access-Control-Request-Headers and the response is "load cancelled".

I think the problem here is the security restrictions on cross-origin requests. The OPTIONS request expects a response that includes an Access-Control-Allow-Origin header from web2py. I know the magical incantations that are needed for this in PHP (as below) but am unclear how this can be done from web2py.  The access_control headers do not appear to be included in request.env.

Basically I need to do the web2py equivalent of this PHP code:

if (isset($_SERVER['HTTP_ORIGIN'])) {
    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Max-Age: 86400');    // cache for 1 day
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
        header("Access-Control-Allow-Methods: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']}");         
    if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
        header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
    }
    exit(0);
}

Massimo Di Pierro

unread,
Aug 1, 2012, 11:13:30 PM8/1/12
to web...@googlegroups.com
I think you want:

if request.env.http_origin:
    response.headers['Access-Control-Allow-Origin'] = request.env.http_origin
    response.headers['Access-Control-Allow-Credentials'] = 'true'
    response.headers['Access-Control-Max-Age'] = 86400
if request.env.request_method == 'OPTIONS':
    if request.env.http_access_control_request_method:
         response.headers['Access-Control-Allow-Methods'] = request.env.http_access_control_request_method
    if request.env.http_access_control_request_headers:
         response.headers['Access-Control-Allow-Headers'] = request.env.http_access_control_request_headers
    raise HTTP(200) # not sure about this line


simon

unread,
Aug 2, 2012, 4:56:31 AM8/2/12
to web...@googlegroups.com
Excellent thanks. That works either in the model or controller. 

You must also add  the header suggested by Anthony to the ajax call. If you don't then not only is request.ajax=false but it does not do the two part request with OPTIONS and GET so does not set the access control headers and does not return any response.

You can use "return" instead of "raise HTTP(200)". 

simon

unread,
Aug 5, 2012, 9:52:29 AM8/5/12
to web...@googlegroups.com
I have since discovered a much simpler and faster way to make cross domain requests to web2py.

 In jquery ajax there is a crossDomain parameter. If you set crossDomain=True then you do not need to add the X-Requested-With header; it only makes one call to the server reducing the response time by 30-50%; you do not need to check for OPTIONS on the server;and you do not need to set Access-Control-Allow-Credentials or Access-Control-Max-Age. 

In summary all you need in your web2py controller is:

    if request.env.http_origin:
            response.headers['Access-Control-Allow-Origin'] = request.env.http_origin      # or restrict access to specific origins
    .....do whatever you want
    return dict()
Reply all
Reply to author
Forward
0 new messages