Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC : Return CSS

My goal is to merge/minify all css files and return the result as String.

Here's my Spring test method :

@RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET, produces = "text/css")
@ResponseBody
public void css(HttpServletResponse response) {
    File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));

    File[] files = path.listFiles(...);

    for (File file : files) {
        InputStream is = new FileInputStream(file);
        IOUtils.copy(is, response.getOutputStream());
        response.flushBuffer();

        is.close();
    }
}

This is working with Chrome, Firefox and Safari but not with IE and Opera.

After some checks in the inspectors, the URL https://host/project/stylesheet.css is loading in each browsers. I can see the content but it does not seem to be recognized as text/css.

Also, even with produces = "text/css", I can not see the content-type http header in all browsers.

Error log in IE :

CSS ignored because of mime type incompatibility

Does anyone know how to correctly do this?

Working code :

@RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET)
public ResponseEntity<Void> css(HttpServletResponse response) {
    response.setContentType("text/css");

    File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));

    File[] files = path.listFiles(...);

    for (File file : files) {
        InputStream is = new FileInputStream(file);
        IOUtils.copy(is, response.getOutputStream());
        IOUtils.closeQuietly(is);
    }

    response.flushBuffer();

    return new ResponseEntity<Void>(HttpStatus.OK);
}
like image 323
Ludovic Guillaume Avatar asked Dec 16 '22 01:12

Ludovic Guillaume


2 Answers

I suspect the problem is due to your usage of HttpServletResponse.flushBuffer().

As the API of HttpServletRequest states:

Forces any content in the buffer to be written to the client. A call to this method automatically commits the response, meaning the status code and headers will be written.

My assumption would be that Spring attempts to set the Content-Type header on the HttpServletResponse after the method on your controller has returned. However, because you have committed the response with your call to HttpServletResponse.flushBuffer(), it cannot do this.

I would try either:

  • Injecting the HttpServletResponse into your controller and setting the header yourself in code before calling HttpServletResponse.flushBuffer()
  • Removing your usage of HttpServletRequest.flushBuffer()
like image 76
Rob Blake Avatar answered Jan 02 '23 13:01

Rob Blake


Since you're writing the content directly to the output stream, you don't need to use @ResponseBody. You just need to ensure that you set the Content-Type response header. Also, it'd be better to return a ResponseEntity (rather than void) to indicate to Spring that you're handling the response yourself.

@RequestMapping(value = "/stylesheet.css", method = RequestMethod.GET)
public ResponseEntity css(HttpServletResponse response) {

    // Set the content-type
    response.setHeader("Content-Type", "text/css");

    File path = new File(servletContext.getRealPath("/WEB-INF/includes/css/"));

    File[] files = path.listFiles(...);

    for (File file : files) {
        InputStream is = new FileInputStream(file);
        IOUtils.copy(is, response.getOutputStream());
        IOUtils.closeQuietly(is);
    }

    response.flushBuffer();

    return new ResponseEntity(HttpStatus.OK)
}
like image 27
Will Keeling Avatar answered Jan 02 '23 12:01

Will Keeling