简体   繁体   中英

Grails REST controller responds with incorrect content type

I'm trying to write a Grails REST controller that should always respond with JSON. The controller is shown below:

class TimelineController {

    static allowedMethods = [index: "GET"]
    static responseFormats = ['json']

    TimelineService timelineService

    def index(TimeLineCommand command) {
        List<TimelineItem> timeline = timelineService.currentUserTimeline(command)
        respond timeline
    }
}

I'm using the respond method which is part of Grails' REST support, so content negotiation is used to figure out what type of response to render. In this particular case I would expect JSON to be chosen because the controller specifies

    static responseFormats = ['json']

Furthermore I've written (and registered with Spring) the following renderer to customise the format of the JSON that is returned for the List<TimelineItem>

class TimelineRenderer implements ContainerRenderer<List, TimelineItem> {

    @Override
    Class<List> getTargetType() {
        List
    }

    @Override
    Class<TimelineItem> getComponentType() {
        TimelineItem
    }

    @Override
    void render(List timeline, RenderContext context) {

        context.contentType = MimeType.JSON.name
        def builder = new JsonBuilder()

        builder.call(
            [items: timeline.collect { TimelineItem timelineItem ->

                def domainInstance = timelineItem.item

                return [
                        date: timelineItem.date,
                        type: domainInstance.class.simpleName,
                        item: [
                                id   : domainInstance.id,
                                value: domainInstance.toString()
                        ]
                ]
            }]
        )

        builder.writeTo(context.writer)
    }

    @Override
    MimeType[] getMimeTypes() {
        [MimeType.JSON] as MimeType[]
    }
}

I've written some functional tests, and can see that although my renderer is invoked, the resolved content type is text/html , so the controller returns a 404 because it can't find a GSP with the expected name.

I strongly suspect the problem is related to the use of a custom renderer, because I have another almost identical controller which doesn't use a custom renderer and it resolves the content type correctly.

Looks like you have to create a blank (at least) index.gsp under

grails-app/views/timeline/

to make the renderer work. I am successfully getting back content type as application/json

This behavior baffles me a lot and I am still looking into it. This is worth a JIRA issue. If you need I can push my dummy app to github.

UPDATE:
Issue created in github (with links to sample app).
https://github.com/grails/grails-core/issues/716

  1. In Config.groovy, grails.mime.types needs to be specified. The details could be found out here: Grails 2.3.11 Content Negotiation . At least you need to have the following in Config.groovy:

     grails.mime.types = [ json: ['application/json', 'text/json'] ] 
  2. If you want to respond with customized JSON, render someMap as JSON is recommended.

  3. About your 404 problem, you need to do response.setContentType('application/json') in your controller action. Grails' default response format is html, so that it will look for the gsp file to render if the contentType is not specified.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM