Grails REST 控制器响应不正确的内容类型
Posted
技术标签:
【中文标题】Grails REST 控制器响应不正确的内容类型【英文标题】:Grails REST controller responds with incorrect content type 【发布时间】:2015-07-27 16:47:48 【问题描述】:我正在尝试编写一个应始终以 JSON 响应的 Grails REST 控制器。控制器如下图:
class TimelineController
static allowedMethods = [index: "GET"]
static responseFormats = ['json']
TimelineService timelineService
def index(TimeLineCommand command)
List<TimelineItem> timeline = timelineService.currentUserTimeline(command)
respond timeline
我正在使用 respond
方法,它是 Grails 的 REST 支持的一部分,因此内容协商用于确定要呈现的响应类型。在这种特殊情况下,我希望选择 JSON,因为控制器指定
static responseFormats = ['json']
此外,我编写(并在 Spring 中注册)以下渲染器来自定义为 List<TimelineItem>
返回的 JSON 格式
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[]
我写了一些功能测试,可以看到虽然我的渲染器被调用了,但是解析出来的内容类型是text/html
,所以控制器返回了404,因为它找不到具有预期名称的GSP。
我强烈怀疑这个问题与使用自定义渲染器有关,因为我有另一个几乎相同的控制器,它不使用自定义渲染器并且它正确解析了内容类型。
【问题讨论】:
Accept
标头是否设置为 application/json
?
@dmahapatro 我不想使用 Accept
标头进行内容解析,我总是想返回 JSON。我认为将static responseFormats = ['json']
添加到控制器应该可以确保这一点
您能否详细说明一下您究竟为什么要使用respond
?当您不使用不同的 mime 类型时,您可以完全摆脱 respond
方法,而改用 render myList as JSON
?
@MarioDavid 因为如果respond
被调用,Grails 将使用我的自定义渲染器来生成 JSON。如果我使用myList as JSON
,那么将使用默认渲染器。
应该创建一个 JIRA 问题。我可以在 2.4.4 和 2.5.0 中复制它。仍在调查中。
【参考方案1】:
看起来你必须在index.gsp
下创建一个空白(至少)
grails-app/views/timeline/
使渲染器工作。我已成功取回内容类型为application/json
这种行为让我很困惑,我仍在研究它。这值得一个 JIRA 问题。如果您需要,我可以将我的虚拟应用推送到 github。
更新: 在 github 中创建的问题(带有示例应用的链接)。https://github.com/grails/grails-core/issues/716
【讨论】:
是的,如果您可以将您的虚拟应用推送到 GitHub 和/或提出一个 JIRA,这将非常有帮助。自己做了一些研究后,我开始怀疑不可能有一个类型的容器渲染器,除非你也有一个用于该类型的单独的渲染器。但是,文档没有提到这一点,我看不出有什么合乎逻辑的理由,所以我同意它值得一个 JIRA。 App 类似于问题中描述的内容。这是github中的问题。 github.com/grails/grails-core/issues/716 在 JIRA 问题和演示应用上做得很好,我已对该问题添加了评论【参考方案2】:在 Config.groovy 中,需要指定grails.mime.types
。
详细信息可以在这里找到:Grails 2.3.11 Content Negotiation。至少你需要在 Config.groovy 中有以下内容:
grails.mime.types = [
json: ['application/json', 'text/json']
]
如果您想使用自定义 JSON 响应,建议使用render someMap as JSON
。
关于您的 404 问题,您需要在控制器操作中执行 response.setContentType('application/json')
。 Grails 的默认响应格式是 html,如果没有指定 contentType,它会寻找 gsp 文件来呈现。
【讨论】:
2.如果我使用render someMap as JSON
,那么将使用默认的 JSON 渲染,即不会调用TimelineRenderer
3.我应该不需要设置内容类型头,Grails的内容解析应该选择基于static responseFormats = ['json']
的JSON@
render([timeline:timeline ] as grails.converters.JSON) 试过这个吗?
Grails 控制器有自己的关键字“response”。你可以这样做response.contentType = 'application/json';
response.setContentLength(content.bytes.size());
response.outputStream << content.bytes;
这里的内容是json的序列化字符串。以上是关于Grails REST 控制器响应不正确的内容类型的主要内容,如果未能解决你的问题,请参考以下文章
Grails控制器渲染方法render vs respond
Grails - Spring Security REST - 302 响应网络::ERR_TOO_MANY_REDIRECTS
使用 Grails Spring Security Plugin Core 和 REST 从用户响应中省略密码字段