在Web框架的范畴内,一切都是基于REST的-- 从返回包含CSS、JavaScript的网页的路由路径,到那些返回JSON数据的URL。
无论你怎么看它,两者都是必须的。我们使用一组URL来呈现URL,使用第二组URL给UI提供动态数据。有时我们还需要第三组URL给移动端提供数据。
其中的重复可能需要大量的工作。并且在我看来,这也是不优雅的。为了解决这个问题,很多框架(包含Nancy)提供了一种叫做内容协商(content negotiatio)的机制。
协商什么内容
当你使用浏览器发出请求时(或者代码访问服务器),你就已经提供了很多信息来描述这个请求。
这些信息被称为请求头(request headers):
请看上图中请求头的Accept 行,这一行是用来描述浏览器或调用程序接收的内容类型,在我们的例子中是:
Accept: text/html,application/xhtml+xml,application/xml,image/webp,*/*
其中说,按优先顺序排列,我希望能接收到 html、 xml 或 webp 图像,如果不能提供序列中的任何类型,那随便什么都可以了。
Nancy在收到客户端请求后会留意请求头中Accept部分。基于查找到的资源,也是可以改变输出的请求头。
如果请求头中的Accept 如下:
Accept: application/json
Nancy会检查返回的数据是否是JSON格式的数据,如果不是,就会抛出异常,报出请求失败。假如我们不想请求失败,可以添加 */* 到后面,正如之前的示例,Nancy就能返回默认的内容。
默认情况下,在没有任何额外配置的情况下Nancy就能决定是否返回HTML,XML,或是JSON。如果你要创建一个API,用来返回一个简单的模型,正如我们前面章节介绍的,Nancy一般都能正确地返回。
如果你在浏览器下请求一个URL,Nancy会在视图文件夹中寻找一个名称匹配的文件。
就拿之前的Address对象举例,Nancy 会查找下面的文件:
'~/Views/Address.Html'
如果URL请求是来自网页中Javascript的调用,Accept头信息中会请求JSON类型的内容,Nancy会将对象按照JSON语法进行序列化,并返回。
如果允许Nancy自由支配返回的内容类型,只需要在路由模块中返回一个对象模型即可。这里没有用到之前那些返回字符串,网页或是视图内容的方法。如果使用了其中的方式,Nancy也就用不到对accept头信息进行分析了。最为简洁的方式如下:
Get[@"/{id}"] = parameters => { int recId = parameters.id; var record = Database.Find(recId); return record; };
无论是使用 new 创建一个对象或是从后台存储生成一个对象,Nancy都会根据头信息中的描述决定如何进行响应。
你也可以使用Negotiate响应API来完成同样的任务。区别就是你可以更多的控制响应,比如修改视图文件的名称,或是添加额外的头信息。该响应API的使用方法如下:
Get[@"/{id}"] = parameters => { int recId = parameters.id; var record = Database.Find(recId); return Negotiate .WithModel(record) .WithHeader("X-CustomHeader", "Some custom value"); };
和之前一样,Database对象返回一条记录,不同的是这次不再直接返回对象模型,而是在响应中增加了一个定制化的头信息。通过这种方式可以在响应上增加一系列的添加。通过Visual Studio 的智能提示可以看到如下:
总结
在本章中,你已经简单的了解了Nancy中的内容协商 -- 如此简单的一个概念,无需配置就能执行。
你已经看到了,正确的使用内容协商,一个URL就能实现众多API,降低了维护的复杂性。
下一章,我们会近距离的看下Nancy的响应对象(response),区别下向客户端返回数据和返回网页的差异。