Manipulating Results[翻译]

改变默认的Content-Type

结果的内容类型是自动地通过的指定的相应体的Scala值推断而来。

例如:

val textResult = Ok("Hello World!")  

将会自动的设置Content-Type头为text/plain,而:

将会设置 Content-Type 头为application/xml。

.提示:这是通过play.api.http.ContentTypeOf类型的类完成。

这是十分有用的,但是有时你想改变它,就只是在结果上使用as(newContentType)方法创建一个新的使用不同Content-Type头的类似的结果:

val htmlResult = Ok(<h1>Hello World!</h1>).as("text/html")  

或使用更好的方式:

val htmlResult2 = Ok(<h1>Hello World!</h1>).as(HTML)  

注意:使用HTML替代"text/html"的好处是字符集将会被自动的处理,并且实际的


继续阅读»»»

Handling errors【翻译】

原文:Handling errors

处理错误

HTTP应用可以返回两类主要的错误类型——客户端错误和服务端错误。客户端错误是指连接的客户端触发了什么错误,服务端错误是指有什么错误发生在服务端。

在许多情况下Play会自动的发现客户端错误——这些错误包括如错误的报头值,不支持的内容类型,请求找不到的资源。在多数情况下,Play也会自动的处理服务端错误——如果你的Action代码抛出异常。Play将会捕捉这个并生成一个服务端错误网页发送给客户端。

Play处理这些错误的接口是 HttpErrorHandler。它定义了两个方法,onClientError, 和 onServerError.

增加自定义的错误处理

自定义的错误处理可以通过在根包下创建一个叫做ErrorHandler的类实现,这个类实现了 HttpErrorHandler,例如:

import play.api.http.HttpErrorHandler  
import play.api.mvc._  
import play.api.mvc.Results._  
import scala.concurre

继续阅读»»»

Content negotiation

原文:Content negotiation

内容协商是一个让相同资源(URI)的不同表现成为可能的机制。它是有用的,如,为了写一个支持多种输出格式(XML, JSON, 等等)的Web Services。本质上,服务端驱动的协商是使用了 Accept* 请求的头执行。你可以在HTTP规范中找到更多关于内容协商的信息。

语言

Play在方法play.api.mvc.Controller#lang中使用它,这个方法提供一个隐式的 play.api.i18n.Lang 值给你的Action,因此他们自动的使用了最佳的语言(如果你的应用支持,否则你的应用的默认语言会被使用)。

内容

实际上,Accept 头没有真的包含MIME 类型而是媒体范围(例如,请求接受所有的文本结果会设置为 text/* 范围,而/ 范围意味着所有的结果类型都接受)。Controllers 提供一个较高水平的render 方法来帮助你处理媒体范围。例如考虑下面的Action定义:

val list = Action { implicit request =>  
val items = Item

继续阅读»»»

Action composition【翻译】

原文:Action composition

这章将介绍几种定义常用Action函数的方式。

自定义Action构建器

我们在前面看到过,有几种声明Action的方式——使用Request参数,不使用request参数,使用Body解析器等等。事实上,正如我们将在异步编程章节看到的. 还有更多的方式。

实际上,这些构建Action的方法都是通过一个叫 ActionBuilder 的特质定义的,并且我们用来声明我的Action的Action对象只是这个特质的实例。通过实现你自己的ActionBuilder, 你可以声明一个可被重复使用的Action栈,然后这可以被用来构建Action。

让我们从一个简单的日志装饰的例子开始,我想记录每次对这个Action的调用。第一种方式是在invokeBlock 方法中实现这个功能,这个方法通过ActionBuilder构建每个Action时调用:

import play.api.mvc._

object LoggingAction extends ActionBuilder[Request] {  
def invokeBlock[A](

继续阅读»»»

HTTP routing[翻译]

原文:HTTP routing

内置HTTP路由器

路由器的职责是负责转换每一个进入的HTTP请求给Action

一个HTTP请求可以被看做是由MVC框架的事件。这个事件包含两个主要的信息:

  • 请求路径(e.g. /clients/1542,/photos/list), 包含查询字符串
  • HTTP 方法 (e.g.GET,POST, …).

路由是在可被编译的conf/routes文件中被定义的。这意味着你可以在你的浏览器中直接看到路由的错误信息

依赖注入

Play支持生成两种路由器的类型,一个是依赖注入路由器,另一个是静态路由。默认的是依赖注入路由器,这也是在Play种子Activator模板中的样例,因此我们推荐你使用依赖注入Contrlller。如果你需要使用静态Contrller,你可以通过在你的build.sbt配置文件里添加下面这样的配置来转换到静态路由生成器:

routesGenerator:= StaticRoutesGenerator  

在Play的文档中的代码样例假定你使用了依赖注入路由生成器。如果你没有使用这个,你可以容易的改写代码样例到静态


继续阅读»»»

Actions, Controllers and Results

原文:Actions, Controllers and Results

什么是Action?

一个Play应用接收的大多数请求都是通过Action处理的。

一个play.api.mvc.Action就是一个(play.api.mvc.Request =>play.api.mvc.Result)函数,这个函数处理请求并生成发送给客户端的结果。

def echo = Action { request =>  
Ok("Got request [" + request + "]")  
}

一个Action返回一个play.api.mvc.Result值,这个值代表HTTP发送给网络客户端的响应。在这个例子中Ok构建了一个含有text/plain响应体的200 OK的响应。

构建一个Action

play.api.mvc.Action伴生对象提供了几个比较有用的方法来构建Action值。

第一个最简单的方式仅用一个表达式块作为参数,返回结果:

Action {  
Ok("Hello world")  
}

这是创建Action的最简单的方式,但是我们不能


继续阅读»»»

用分层结构打造苗条MVC框架

原文请访问:Maintain Slim PHP MVC Frameworks with a Layered Structure

基于诸如Yii和Laravel这样MVC框架的一个必然问题就是:臃肿的controller(控制器)和臃肿的model(模型)。而使控制器和模型变得臃肿的主要东西就是这些框架中强大而又必要的组件 -- Active Record。

问题:违反了单一职责原则的Active Record

Active Record是一个架构模式,一种访问数据库中数据的方式。由Martin Fowler在他2003年的《企业应用框架模式》一书命名并广泛应用在PHP框架中。

尽管它一是个非常必要的方式,然而Active Record(AR)模式违反了单一职责原则(SRP),因为AR模型:

  • 处理了数据查询与数据存储。
  • (通过关系)知道了系统中太多其他的模型。
  • 经常在应用的业务逻辑中直接调用(因为数据存储的实现与业务逻辑的表达密切相关)。

当需要尽快创建一个应用原型时,违反SRP对于快速开发来说是一桩好的交易,但当应用成长为一个中等或者大型项目时,


继续阅读»»»

合成监控(SyntheticMonitoring)

/**
 * 献给我最尊敬的偶像Martin Fowler
 * 原文出处:https://martinfowler.com/bliki/SyntheticMonitoring.html
 * @author dogstar.huang <chanzonghuang@gmail.com> 2017-03-26
 */

本翻译已征得Martin Fowler同意,并链接在博客原文下方。

合成监控(也称为语义监控 [1])会定期对线上生产系统执行应用程序中自动化测试的一个子集。其结果会推送到监控服务,如果失败则触发警告。这项技术结合了自动化测试和监控以便能检测生产环境中失败的业务需求。

在小型独立服务和频繁部署的时代,很难用与后面会出现在生产环境上完全相同的版本组合来测试预生产环境。缓解这个问题的一个途径是将可测试性从预生产环境扩展到生产环境 -- 即生产环境上的QA背后的想法。这样做,可把思维模式从关注平均故障时长(MTBF)切换到关注平均修复时间(MTTR)。

对于大部分F的类型,平均修复时间 > 平均故障时长。 -- John Allspaw


继续阅读»»»

持续集成认证(ContinuousIntegrationCertification)

/**
 * 献给我最尊敬的偶像Martin Fowler
 * 原文出处:https://martinfowler.com/bliki/ContinuousIntegrationCertification.html
 * @author dogstar.huang <chanzonghuang@gmail.com> 2017-03-22
 */

本翻译已征得Martin Fowler同意,并链接在博客原文下方。

持续集成是软件开发中一项流行的技术。很多开发人员在会议上讨论他们如何使用它,并且持续集成工具在大部分开发组织里很常见。但我们都知道任何正规的技术都需要认证流程 -- 而幸运的是确实存在那么一个。它由持续交付和devops最杰出的专家之一开发而来,以显著快速的管理而闻名,但对其结果非常有见解。尽管它很成熟,但它没有得到应有的流行,所以作为这项技术的粉丝之一,我觉得和读者分享这个认证流程对我来说是件重要的事情。准备好得到持续集成的认证了吗?你会如何处理测试过程中揭露的令人震惊的事实呢?

到现在,我以往的读者会在想他们是不是看到了一篇恶搞的博客 [1]


继续阅读»»»

隐藏的精度(HiddenPrecision)

/**
 * 献给我最尊敬的偶像Martin Fowler
 * 原文出处:https://martinfowler.com/bliki/HiddenPrecision.html
 * @author dogstar.huang <chanzonghuang@gmail.com> 2017-03-22
 */

本翻译已征得Martin Fowler同意,并链接在博客原文下方。

有时当我在处理某些数据时,这些数据比我想象中的更精确。有人可能会觉得这应该是件好事,毕竟精确度是有益的,所以越精细越好。但隐藏的精度可能会导致一些微妙的缺陷。

const validityStart = new Date("2016-10-01");   // JavaScript  
const validityEnd = new Date("2016-11-08");  
const isWithinValidity = aDate => (aDate >= validityStart && aDate <= validityEnd);  
con

继续阅读»»»