tags:

views:

110

answers:

2

The following action is meant to write the binary content of bytes directly to the client completely bypassing the Grails view layer:

def actionName = {
  byte[] bytes = ...
  ServletOutputStream out = response.getOutputStream()
  out.write(bytes)
  out.flush()
  out.close()
  return false
}

I was under the impression that return false would make Grails completely skip the view layer. However, that appears not to be the case since the above code still makes Grails search for /WEB-INF/grails-app/views/controllerName/actionName.jsp (which fails with a 404, since no such file exists).

Question:

  • Given the code above, how do I completely bypass the view layer in Grails?
+3  A: 

You should return null or nothing at all, which is interpreted as null. Here's some working code from an action that sends a dynamically generated PDF:

def pdf = {
   byte[] content = ...
   String filename = ...
   response.contentType = 'application/octet-stream'
   response.setHeader 'Content-disposition', "attachment; filename=\"$filename\""
   response.outputStream << content
   response.outputStream.flush()
}
Burt Beckwith
Hi Burt! Thanks for the answer and nice code. However, the code does not solve the "completely bypass the view layer". Please see my answer below. Do you know why response.contentType == null is needed for it to work? Is it a bug or a feature?
knorv
A: 

It appears as Grails tries to render the view if response.contentType.startsWith('text/html'). This seems to be a known bug, see GRAILS-1223.

Here are two work arounds:

  1. Use render(contentType: "text/html", text: htmlString) as suggested in GRAILS-1223. This will bypass the view layer.
  2. Clear the content type with response.contentType = ''. This will also bypass the view layer. However, note that the content will be served to the end-user without Content-Type which can confuse some browsers.
knorv