jsonp catching bad request response (400) and such?

241 views
Skip to first unread message

Rolf -nl

unread,
Jul 6, 2011, 5:22:35 PM7/6/11
to MooTools Users
Working with some api that can return a bad request code 400 error
with the error message as a response in json. Is there a way I can use
it? Because the response contains useful information about wrongly
used params? There's a failure event, but that works with the timeout
and I that's not really usable or the same.

Ger Hobbelt

unread,
Jul 6, 2011, 5:40:34 PM7/6/11
to mootool...@googlegroups.com
IIRC there's a OnError and a OnFailure event handler for the Request.JSON class: the one is for catching connection timeouts, while the other can catch parse errors, including 40x return code responses.

...

quick check: yep, used it that way in mootools-filemanager. 
It's a bit tricky is the one originates from Request while the other originates from Request.JSON if you dig in and RTFC of mootools. That's how I found out about this earlier, anyway. :-)

(relevant code snippets at bottom of this message.)

HTH
...

cvtXHRerror2msg: function(xmlHttpRequest) {
var status = xmlHttpRequest.status;
var orsc = xmlHttpRequest.onreadystatechange;
var response = (xmlHttpRequest.responseText || this.language['backend.unidentified_error']);

var text = response.substitute(this.language, /\\?\$\{([^{}]+)\}/g);
return text;
},

....

// filemanager.request is just an slightly augmented Request.JSON derivative class; 
// filebrowser.showError() shows the human-readable error response, when one occurs.


FileManager.Request = new Class({
Extends: Request.JSON,

options:
{
secure:          true, // Isn't this true by default anyway in REQUEST.JSON?
fmDisplayErrors: true  // Automatically display errors - ** your onSuccess still gets called, just ignore if it's an error **
},

initialize: function(options, filebrowser) {
this.parent(options);

this.options.data = Object.merge({}, filebrowser.options.propagateData, this.options.data);

if (this.options.fmDisplayErrors)
{
this.addEvents({
success: function(j)
{
if (!j)
{
filebrowser.showError();
}
else if (!j.status)
{
filebrowser.showError(('' + j.error).substitute(filebrowser.language, /\\?\$\{([^{}]+)\}/g));
}
}.bind(this),

error: function(text, error)
{
filebrowser.showError(text);
},

failure: function(xmlHttpRequest)
{
var text = filebrowser.cvtXHRerror2msg(xmlHttpRequest);
filebrowser.showError(text);
}
});
}

this.addEvents({
request: filebrowser.onRequest.bind(filebrowser),
complete: filebrowser.onComplete.bind(filebrowser),
success: filebrowser.onSuccess.bind(filebrowser),
error: filebrowser.onError.bind(filebrowser),
failure: filebrowser.onFailure.bind(filebrowser)
});
}
});



Server-side PHP has blurbs like these to send 'useful' error texts with 40x responses, here a 403:

/**
* Process the 'download' event
*
* Send the file content of the specified file for download by the client.
* Only files residing within the directory tree rooted by the
* 'basedir' (options['URLpath4FileManagedDirTree']) will be allowed to be downloaded.
*
* Expected parameters:
*
* $_POST['file']         filepath of the file to be downloaded
*
* $_POST['filter']       optional mimetype filter string, amy be the part up to and
*                        including the slash '/' or the full mimetype. Only files
*                        matching this (set of) mimetypes will be listed.
*                        Examples: 'image/' or 'application/zip'
*
* On errors a HTTP 403 error response will be sent instead.
*/
protected function onDownload()
{
$emsg = null;
$file_arg = null;
$file = null;
$jserr = array(
'status' => 1
);

try
{
if (!$this->options['download'])
throw new FileManagerException('disabled:download');

[... doing stuff ...]
$this->sendHttpHeaders($hdrs);

fpassthru($fd);
fclose($fd);
return;
}

$emsg = 'read_error';
}
catch(FileManagerException $e)
{
$emsg = $e->getMessage();
}
catch(Exception $e)
{
// catching other severe failures; since this can be anything and should only happen in the direst of circumstances, we don't bother translating
$emsg = $e->getMessage();
}

// we don't care whether it's a 404, a 403 or something else entirely: we feed 'em a 403 and that's final!
send_response_status_header(403);

$this->modify_json4exception($jserr, $emsg, 'file = ' . $this->mkSafe4Display($file_arg . ', destination path = ' . $file));

$this->sendHttpHeaders('Content-Type: text/plain');        // Safer for iframes: the 'application/json' mime type would cause FF3.X to pop up a save/view dialog when transmitting these error reports!

// when we fail here, it's pretty darn bad and nothing to it.
// just push the error JSON and go.
echo json_encode($jserr);
}



--
Met vriendelijke groeten / Best regards,

Ger Hobbelt

--------------------------------------------------
web:    http://www.hobbelt.com/
        http://www.hebbut.net/
mail:   g...@hobbelt.com
mobile: +31-6-11 120 978
--------------------------------------------------

Ger Hobbelt

unread,
Jul 6, 2011, 5:47:36 PM7/6/11
to mootool...@googlegroups.com
Almost forgot for the PHP bit:

// we don't care whether it's a 404, a 403 or something else entirely: we feed 'em a 403 and that's final!
send_response_status_header(403);

It's all in:


the snip&rip-able stuff like send_response_status_header() is all in Tooling.php
In case you were looking for all the gory details. :-)


Ryan Florence

unread,
Jul 6, 2011, 5:51:52 PM7/6/11
to mootool...@googlegroups.com
JSONP is simply creating script elements on the page.

You can open web inspector / firebug and look at the file there like any other script you include on the page.

Aaron Newton

unread,
Jul 6, 2011, 8:03:59 PM7/6/11
to mootool...@googlegroups.com
JSONP can't catch 400 errors because it's a callback system waiting for the script to load. If the script fails, the callback is not invoked and so it has no way of knowing that the script failed. The best it can do is be given a timeout. If the request takes too long, or the script tag that is injected fails to load, the timeout fires and you know it didn't load.

Fábio M. Costa

unread,
Jul 6, 2011, 11:24:46 PM7/6/11
to mootool...@googlegroups.com
I've been thinking about an implementation of error detection.
You can check if the script tag is loaded, this is cross-browser, so... If the script has loaded (independent of the http status code) and the callback has not executed, lets say 200 ms after, we can say that we got some kind of error. 

Still i can't tell you too much about what error it gave... but something didn't go ok and your data was not retrieved.

Feedbacks?

--
Fábio Miranda Costa
frontend@portalpadroes
Globo.com
github: fabiomcosta
twitter: @fabiomiranda
ramal: 6476

Aaron Newton

unread,
Jul 6, 2011, 11:28:13 PM7/6/11
to mootool...@googlegroups.com
It's been so long since I wrote that code I can't say whether or not this is true. I do recall spending time trying to offer a more robust error reporting mechanism on it...

2011/7/6 Fábio M. Costa <fabio...@corp.globo.com>

Rolf -nl

unread,
Jul 7, 2011, 4:40:28 PM7/7/11
to MooTools Users
Thanks for the replies guys, I understand what you're trying to say
and I understand how it works.
@Ryan; I can read the error in the consoles just fine ;) I just wanted
to use it for output to the user or do something with it (fix it when
possible) and continue).

Catching an error like Fabio suggested is something, at least.. I mean
it's fair to say there's an error if the callback didn't fire after
the script is loaded.

In the case I'm using it (echonest btw) it loads the script fine, it's
just the send params can be wrong and then it returns the 400 response
with an error message in json telling which param was wrong... so it's
a handy error response really. I was throwing together an API wrapper
for it and thought about describing all available methods with input
checking before sending the request (and that way catch possible error
before sending), but if I could read the actual response it would be
easier and I could throw the error to the user as well ("hey, param X
is invalid, fix your sh*t, check the docs").

I don't have to use jsonp, could use a standard request and check
error codes with it, but tried jsonp cause I didn't work with it
before.


On Jul 7, 5:24 am, Fábio M. Costa <fabio.co...@corp.globo.com> wrote:
> I've been thinking about an implementation of error detection.
> You can check if the script tag is loaded, this is cross-browser, so... If
> the script has loaded (independent of the http status code) and the callback
> has not executed, lets say 200 ms after, we can say that we got some kind of
> error.
>
> Still i can't tell you too much about what error it gave... but something
> didn't go ok and your data was not retrieved.
>
> Feedbacks?
>
> --
> Fábio Miranda Costa
> frontend@portalpadroes
> Globo.com
> *github:* fabiomcosta
> *twitter:* @fabiomiranda
> *ramal:* 6476
>
>
>
> On Wed, Jul 6, 2011 at 9:03 PM, Aaron Newton <aa...@iminta.com> wrote:
> > JSONP can't catch 400 errors because it's a callback system waiting for the
> > script to load. If the script fails, the callback is not invoked and so it
> > has no way of knowing that the script failed. The best it can do is be given
> > a timeout. If the request takes too long, or the script tag that is injected
> > fails to load, the timeout fires and you know it didn't load.
>

Ryan Florence

unread,
Jul 7, 2011, 4:55:50 PM7/7/11
to mootool...@googlegroups.com
> @Ryan; I can read the error in the consoles just fine ;) I just wanted
> to use it for output to the user or do something with it (fix it when
> possible) and continue).


Sorry, didn't read that carefully enough :P

RequireJS waits 7 seconds by default before throwing a timeout error. I think that's the only way to do it with script injection.


Olmo

unread,
Jul 21, 2011, 1:54:28 AM7/21/11
to mootool...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages