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.
Related
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
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.
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.
I have an ASP.NET MVC 4 application and I want to redirect all HTTP 400 errors to my custom error page. I was searching an hours to find a solution though HTTP 400 error isn't handled like 404 error. There are many solutions that show how to escape 400(bad request error), i.e. to allow using special characters for example in url. But I wouldn't able to find some solution to catch the exception.
Please help me to catch somehow all HTTP bad requests and redirect them to my error page.
Never redirect users in case of errors, instead return a response body for the failed request. The feature of IIS (and ASP.NET) to redirect to an error page, I believe, is fundamentally wrong, incorrect, and against the HTTP specification (because then the error is being returned for the error page resource itself, not the original request. And if it's a web-browser the user has no way of retrying, because reloading the page will return the error page again, not retrying their original failed request, which is what they want).
Anyway...
A HTTP 400 response must be generated by your application code, it isn't something that will be done automatically. A bad request is typically used when informing non-human agents (i.e. web service clients, not web browsers) that their HTTP request was missing required values or had malformed values.
You can do this in MVC by having a base controller class for all of your controllers like so:
public abstract class BaseController : Controller {
protected ActionResult Http400(String message) {
Response.StatusCode = 400;
return View(message); // you need to define a view file called "Http400.aspx" (or cshtml if you're using Razor) in your application's shared views folder
}
}
so in your application logic:
public ActionResult Foobar() {
if( IsBadRequest() ) return Http400("Bad request, try again");
}
You could do something as simple as adding adding this to your web.config
<customErrors mode="RemoteOnly">
<error statusCode="400" redirect="errorpage.html"/>
</customErrors>
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>