Grails WEB层 内容协商

 

6.8 内容协商

Grails已经内置支持内容协商通过使用任意HTTP Accept 报头,一种明确格式请求参数或URI映射的扩展.

 

配置Mime类型

在你开始处理内容协商之前,你必须告诉Grails希望支持什么样的内容类型。 默认情况下,grails-app/conf/Config.groovy内使用 grails.mime.types设置来配置若干不同的内容类型 :

 

grails.mime.types = [ xml: ['text/xml', 'application/xml'],
                      text: 'text-plain',
                      js: 'text/javascript',
                      rss: 'application/rss+xml',
                      atom: 'application/atom+xml',
                      css: 'text/css',
                      cvs: 'text/csv',
                      all: '*/*',
                      json: 'text/json',
                      html: ['text/html','application/xhtml+xml']
                    ]

上面的小块配置,允许Grails检查把包含 'text/xml' 或 'application/xml' 媒体类型的一个请求的格式只当做 'xml'看待,你可以添加你自己的类型通过简单的添加条目到 map中.

 

内容协商使用Accept报头

每个进入的HTTP请求都有个指定的Accept报头,它定义了什么样的媒体类型(或 mime 类型)客户端能"接受"。在老式浏览器中通常是 :

 

*/*

这意味着任何事物.不过在新生浏览器中,所有东西一起像这样发送更有用(一个FirefoxAccept报头示例) :

 

text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5

Grails解析这个进入的格式,并添加一个propertyrequest对象,用于描叙首选的请求格式。对于上述示例下列的断言会通过 :

 

assert 'html' == request.format

为什么?这个text/html媒体类型拥有最高"质量"等级0.9,因此,具有最高优先权。如前所述,假如你有一老式浏览器结果会稍微不同 :

 

assert 'all' == request.format

在这种情况下,'all'可能的格式会被客户端接受。为了处理来自控制器(Controllers)不同类型的请求,你可以使用withFormat方法,它的行为被当作switch表达式 :

 

import grails.converters.*

class BookController { def books def list = { this.books = Book.list() withFormat { html bookList:books js { render "alert('hello')" } xml { render books as XML } } } }

当Grails只执行 html()调用并且首选的格式是html时会发生什么。它只是让 Grails寻找每个名为grails-app/views/books/list.html.gspgrails-app/views/books/list.gsp的视图。如果格式是xml,那么,闭包会被调用,XML响应会被渲染 .

我们怎样处理'all'格式?只需在withFormat代码块中简单指定content-types,以便,无论你想要的哪个都会被首先执行。因此,在上面示例中的"all" 将触发html处理 .

 

当使用 withFormat时确保它在控制器(controller)操作(action)中最后一个被调用,因为 withFormat方法的返回值用来决定操作(action)下一步做什么.

 

内容协商与格式化请求参数

如果请求头的内容跟你的不一致,通过指定一个format的请求参数覆盖这个格式 :

 

/book/list?format=xml

你同样可以在URL Mappings定义中定义这个参数 :

 

"/book/list"(controller:"book", action:"list") {
	format = "xml"
}

 

内容协商与URI扩展

Grails同样可以通过URI扩展支持内容协商。例如,给定下列URI:

 

/book/list.xml

Grails将剔除扩展并映射到/book/list作为替代,同时,基于这个扩展把内容格式化为xml。这个行为是默认允许的,那么,假如你希望关闭它, 你必须把grails-app/conf/Config.groovy下的grails.mime.file.extensions属性设置为false :

 

grails.mime.file.extensions = false

 

测试内容协商

为了在一个综合测试中测试内容协商(参见 测试部分)你可以操作每个进入的请求包头 :

 

void testJavascriptOutput() {
	def controller = new TestController()
	controller.request.addHeader "Accept", "text/javascript, text/html, application/xml, text/xml, */*"

controller.testAction() assertEquals "alert('hello')", controller.response.contentAsString }

或者你可以设置格式化参数来实现类似的效果:

 

void testJavascriptOutput() {
	def controller = new TestController()
	controller.params.format = 'js'

controller.testAction() assertEquals "alert('hello')", controller.response.contentAsString }

你可能感兴趣的:(xml,json,Web,grails,groovy)