I have grails application.
I want to implement global grails back end exception handler.
Means if there are any exception in application at back end like NullPointer, ArrayIndexOutOfBounds or any other exception is raised then some code should be executed. How we can do this in grails 2.4.4.
You can hadle it using UrlMappings.
From the documentation
static mappings = {
"403"(view: "/errors/forbidden")
"404"(view: "/errors/notFound")
"500"(controller: "errors", action: "illegalArgument",
exception: IllegalArgumentException)
"500"(controller: "errors", action: "nullPointer",
exception: NullPointerException)
"500"(controller: "errors", action: "customException",
exception: MyException)
"500"(view: "/errors/serverError")
}
With this configuration, an IllegalArgumentException will be handled by the illegalArgument action in ErrorsController, a NullPointerException will be handled by the nullPointer action, and a MyException will be handled by the customException action. Other exceptions will be handled by the catch-all rule and use the /errors/serverError view.
Use Grails declarative exception handling for controllers
def handleLException(Exception e) {
render "Opps: ${e.message}"
}
More information here: http://docs.grails.org/2.4.5/guide/single.html#controllerExceptionHandling
Related
I've inherited a grails project in which an Error Controller is used.
Within the URLMappings there is the following entry:
"500"(controller: 'error', action:'error')
The specific errorController renders a specific view:
render view:'/error/prodError'
What I don't understand is how to bypass error controller for 500 errors and send to view /play/play but without removing the old one for other situations.
Even though I catch exceptions from the playService, I still get /error/prodError instead of /play/play.
I've debugged the code and seen that the render method is called twice. It is called once to go to /play/play but another time for /error/prodError when an exception is thrown in the service and the transaction is rolled back.
See playController excerpt below:
PlayController
try{
playService.play(parame:params} //Runtime exception thrown from playService.
//play is transactional
}
catch(Throwable t){
//Why isn't /play/play rendered?
//How do I pass errors to playservice for alert rendering?
render view: '/play/play',
model: [
domain: domain,
customer: customer,
game: game]
return
}
Update
Specifically, the errorController is entered because of an UnexpectedRollbackException that is the result of the rollback.
SO: How would someone go about not entering the ErrorController for a specific type of Exception that results from a specific Controller?
If you don't want to handle the error within a controller, you could render your (or any other) view with the following url mapping:
"500"(view:'/play/play')
If you need to handle individual exception you do it like this:
static mappings = {
.
.
.
"500"(controller: "error", action: "unexpectedRollback", exception: UnexpectedRollbackException)
"500"(controller: "errors", action: "nullPointer", exception: NullPointerException)
.
.
"500"(controller: 'error', action:'error')
}
As mentioned in docs you should avoid throwning exceptions from your error controller due to StackOverflowExceptions. I think it's not possible to divide between two exceptions of the same type but thrown from diffent controller.
If you handle the exception within your error controller you could try to set the response code directly. So - the url mapping may not handle your already handled exception.
If I have a UrlMappings.groovy that specifies:
"403"(controller: 'error', action: 'status403')
... then I was hoping to trigger this route at runtime by assigning:
response.status = 403
from within a controller or filter. But that doesn't happen. Is there a similarly declarative way for me to "kick a request over" to 403 handling from within a controller or filter?
response.sendError(403)
or
render(status: 403)
See your other question.
I'd like to create an AuthorizationFilter in my Grails app that will inspect request parameters and determine whether a user is authorized to proceed with a request. I was hoping I could throw a custom exception from within my AuthorizationFilter and later handle it with Grails declarative execption handling via a route like:
"403"(controller: 'error', action: 'status403', exception:AuthException)
... but turns out when I try this in grails 2.2.4 (and the latest dev snapshot) I get
java.lang.IllegalArgumentException: Method name must not be null
at grails.plugin.cache.web.ProxyAwareMixedGrailsControllerHelper.retrieveAction(ProxyAwareMixedGrailsControllerHelper.java:41)
So... is there any good way to use declarative exception handling together with filters?
I guess you can handle declarative exception from Controllers but Filters. You can use response instead to send the error code
class AuthorizationFilters {
def filters = {
auth(controller: 'error', invert: true) {
before = {
if(1){ //If auth fails
response.sendError(403)
//render(status: 403) //or
//redirect(controller: 'error', action: 'status403') //or
}
return false
}
}
}
}
Above logic will render the response from ErrorController's status403 action based on the UrlMapping that is provided in the question
Make sure you are excluding error controller from filters.
If I am making a regular request I can define handling of errors and exceptions in UrlMappings.groovy as in the following example:
"403"(controller: 'error', action: 'index', params:['code':'403'])
"404"(controller: 'error', action: 'index', params:['code':'404'])
"500"(controller: 'error', action: 'index', params:['code':'500'])
"500"(controller: 'home', action: 'noPrivileges', exception: IllegalOperationException)
I can then handle the errors in a specific controller and render a view of my choice e.g.
class ErrorController {
def index = {
render view: "/errors/myErrorPage", model: [code: params.code]
}
}
This works perfectly and whenever there is an error on server I get my error page.
Now how can I achieve the very same behavior for ajax requests? I am making ajax requests either with grails remoteFunction or formRemote. Everytime when an exception occurs on the server, I want to execute the same piece of code in javascript (e.g. I want to show an alert with alert('There was an exception')).
The above described approach does not work for ajax requests. I still get back an error and even though there is content of myErrorPage.gsp in the error, it is not printed into the html element which I specified with update parameter of formRemote or remoteFunction.
I finally found a perfectly clean solution compatible with the approach which is used for handling standard requests.
You need to modify action which is handling the error as in the following example:
class ErrorController {
def index = {
if (request.xhr) {
response.status = 200
render template: "/errors/myAjaxErrorTemplate", model: [code: params.code]
} else {
render view: "/errors/myErrorPage", model: [code: params.code]
}
}
}
With request.xhr you can differentiate between ajax request and a standard request. In ajax request you further need to tell grails that the response is OK with setting response status to 200.
Very nice and clean. :) I am surprised this can't be googled anywhere...
The remoteFunction trigger a couple of events onFailure and on_ERROR_CODE. You can use that events to show your warning messages.
You can see more details in docs
If the request status is set correctly you could define an JavaScript function via the onFailure attribute of remoteFunction/formRemote.
Within this function you could handle your exception on client side.
Using the sample from the docs it could look like this:
<select onchange="${remoteFunction(action: 'bookByName',
update: [success: 'great', failure: 'ohno'],
params: '\'bookName=\' + this.value'),
onFailure: 'handleError'}">
<option>first</option>
<option>second</option>
</select>
While debugging my MVC 4 application in VS2010 SP1, the Application_Error() handler was invoked but Server.GetLastError() was null.
protected void Application_Error()
{
var exception = Server.GetLastError();
// exception is null. How is that possible?
}
MSDN states Application_Error is
called if an unhandled exception occurs anywhere in your ... application... You can get information about the most recent error from the GetLastError method.
The MSDN docs for Server.GetLastError() states
Return value: The previous exception that was thrown.
How can I possibly be in a state where Application_Error() was called but Server.GetLastError() returns null?
Are you using custom error handling in your web.config? I believe that if the browser issues a redirect, the previous exception will be lost. Take a look at this answer and see if your situation is similar.