阿江 2017-10-05 06:25:24 3776次浏览 0条回复 1 0 0

说明

学习Yii Framework 2易2框架的过程是漫长的也是充满乐趣的以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现提供了较完整的代码供你参考不妥之处请多多指正

原文网址:

http://www.yiiframework.com/doc-2.0/guide-runtime-responses.html

本文主题:响应(Responses)

当一个应用处理完一个请求后,它会生成一个response对象,并发送给用户。response对象包含的信息如:HTTP状态码、HTTP头和body。网站应用的终极目标就是根据不同的请求去构建相应的响应。 多数情况下,你可以处理response应用组件,它是yii\web\Response的实例。Yii也允许你创建自己的response对象,并发送它们到用户,稍后我们将描述这种情况。

在本节,我们将描述如何去构建和发送响应给用户。

1、状态码(Status Code)

构建一个响应的第一件事是确定此请求是否处理成功了,这可以通过设置yii\web\Response::$statusCode 属性完成,此属性就是HTTP状态码,例如,要描述请求已处理成功,你可以设置状态码为200,如下例:

Yii::$app->response->statusCode=200;

在大多数情况下你都无需显式的设置此状态码,因为yii\web\Response::$statusCode 的默认值就是200;如果你要描述请求未成功,你可以抛出相应的HTTP异常,代码如下: throw new \yii\web\NotFoundHttpException;

当错误处理器捕获到异常,它将从异常中获取状态,并将它赋给response,对于上面的yii\web\NotFoundHttpException,它与HTTP状态404相关联。Yii预定义的HTTP异常如下:

//404
//Exception,status code
yii\web\BadReqeustHttpException,400
yii\web\ConflictHttpException,409
yii\web\ForbiddenHttpException,403
yii\web\GoneHttpException,410
yii\web\MethodNotAllowedHttpException,405
yii\web\NotAcceptableHttpExcepton,406
yii\web\NotFoundHttpException,404
yii\web\ServerErrorHttpException,500
yii\web\TooManyRequestsHttpException,429
yii\web\UnauthorizedHttpException,401
yii\web\UnsupportedMediaTypeHttpException,415

如果你要抛出的异常不在上述列表之中,你可以扩展yii\web\HttpException创建一个,或者直接抛出状态码,如:

throw new \yii\web\HttpException(402);
2、HTTP Headers

你可以处理response组件中的header collection来发送HTTP头信息,例如:

$headers=Yii::$app->response->headers;
//添加一个Pragma头信息,已存在的Pragma头将不会被覆盖。
$headers->add('Pragma', 'no-cache');
//设置Pragma头信息,任何已存在的Pragma头信息将会被清除。
$headers->set('Pragma', 'no-cache');
//删除Pragma头信息,并返回移除的Pragma头信息到一个数组中。
$values = $headers->remove('Pragma');

信息:头名称是大小写敏感的,新注册的头信息只有yii\web\Response::send()方法被调用时才会被发送。

3、Response Body

大多数响应都有一个body,在此存放了你要展现给终端用户的内容。 如果你已经有了一个格式化的body字符串,你可以将它赋给yii\web\Response::$content 属性,例如:

Yii::$app->response->content='hello world!';

如果你的数据需要在发送给客户之前进行格式化,你应该同时设置format和data两个属性,format属性定义了data将被格式化什么格式,例如:

$response=Yii::$app->response;
$response->format=\yii\web\Response::FORMAT_JSON;
$response->data=['message'=>'hello world'];

//data优先级高于content D:\phpwork\basic\controllers\ArticleController.php

	    public function actionView($id) {
	//        Yii::$app->response->data="<span style='color:red'>test</span>";
			Yii::$app->response->content="<span style='color:blue'>test</span>";
			//return省略亦可正常显示content的内容
			return;//只要有return语句即可,无需返回内容。
		}
测试结果:
/*
<span style="color:blue">test</span>
*/

Yii支持如下列表的格式,每种格式均由一个格式化器类(formatter class)实现,你可以自定义这些格式化器,或者通过配置yii\web\Response::$fomatters 属性添加新的格式化器。 1、HTML:由yii\web\HtmlResponseFormatter实现 2、XML:由yii\web\XmlResponseFormatter实现 3、JSON:由yii\web\JsonResponseFormatter实现 4、JSONP:由yii\web\JsonResponseFormatter实现 5、RAW:如果你需要将响应不应用任何格式直接发送出去,可以使用此格式。

响应body可以如上所示的显式设置,但大多数情况下,你可以在动作(action)方法的返回值中设置它即可,常用的作法如下所示:

public function actionIndex(){
	//Yii::$app->response->content=$this->render('index');//与下句等效,无需return语句。本句与下句取其一即可
	return $this->render('index');//此句的return不能少,与上句同时存在的情况下,本句生效。
}

上面的index动作返回index视图的渲染结果,返回值将被response组件所获取,格式化,然后发送给终端用户。

因为默认的响应格式是HTML,你只需在动作方法中返回一个字符串即可,如果你想要使用其他的响应格式,你需要在返回数据前设置它,例如:

public function actionInfo(){
	\Yii::$app->response->format=\yii\web\Response::FORMAT_JSON;
	return [
		'message'=>'hello world',
		'code'=>100,
	];
}

如前所述,除了使用默认的response应用组件,你也可以创建你自己的响应组件,并发送它们到终端用户。你可以在动作方法中返回一个对象,如下例所示:

public function actionInfo(){
	return \Yii::createObject([
		'class'	=>'yii\web\Response',
		'format'=>\yii\web\Response::FORMAT_JSON,
		'data'=>[
			'message'=>'hello world',
			'code'=>100,
		],
	]);
}

注意:如果你创建了自己的响应对象,虽然你在应用配置中设置了响应组件,但你无法从这些配置中获取好处。尽管如此,你仍然可以使用依赖注入在你的新响应对象上应用一个通用配置。

4、Browser Redirection(浏览器跳转)

浏览器跳转依赖于发送一个Location的HTTP头信息。因为这个特征经常被使用,所以Yii提供了一些特殊支持。

你可以调用yii\web\Response::redirect()方法直接将用户浏览器指向一个URL,此方法对给定的URL设置了相应的Location头信息,并返回了它自身的response对象,在动作方法中,你可以调用yii\web\Controller::redirect()的快捷方法,例如:

public function actionOld(){
	return $this->redirect("http://example.com/new",301);
}

在上例代码中,动作将返回redirect()方法的结果。如前所述,动作返回的响应对象将作为响应发送给终端用户。

在动作方法之外的其他地方,你应直接调用yii\web\Response::redirect(),紧跟其后是一个链式调用yii\web\Response::send()方法,以确保没有额外的内容被添加到response:

\Yii::$app->response->redirect('http//example.com/new',301)->send();

信息:默认情况下,yii\web\Response::redirect()方法设置响应状态代码为302,也就是告知浏览器,请求的资源临时(temporarily)指向了另外一个URI;你可以传递另一个状态码301告知浏览器此资源已被永久(permanently)重定向了。

当前请求是AJAX请求时,发送一个Location头信息并不会让浏览器自动跳转,要解决这个问题,yii\web\Response::redirect()方法设置了一个X-Redirect头信息,将跳转的URL作为它的值,在客户端,你可以编写JavaScript代码去读取这个头信息,并将浏览器重定向。

信息:Yii自带了yii.js的JavaScript文件,它提供了一系列常用的JavaScript组件,包括基于X-Redirect头信息的浏览器重定向。所以你使用这个JS文件(通过注册yii\web\YiiAsset即可),你无需为支持AJAX重定向编写任何代码。关于yii.js的更多信息请参考Client Script章节: http://www.yiiframework.com/doc-2.0/guide-output-client-scripts.html#yii.js

//Ajax跳转实例,会跳转到/article/index,但是在Ajax前端会报错,弹出窗口显示:'error:error' D:\phpwork\basic\controllers\ArticleController.php

    public function actionGoindex() {
        if (Yii::$app->request->isAjax) {
            Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
            Yii::$app->response->redirect('index')->send();
        }
    }

D:\phpwork\basic\views\article\view.php

    <button onclick="jump()">跳转</button>
    <?php $this->beginBlock('script'); ?>
    <script>
      function jump(){
          $.ajax({
              url:'/article/goindex',
              type:'post',
              dataType:'json',
              data:{"_csrf": "<?= Yii::$app->request->getCsrfToken()?>"},
              success:function(result){
                  alert('ok');
              },
              error:function(xhr,txtStatus){
                  alert('error:'+txtStatus);
              },
              complete:function(xhr,txtStatus){
              }
          });
      }
    </script>
    <?php $this->endBlock('pageJS'); ?>
5、Sending Files

与浏览器跳转相类似,文件发送是依赖于特定HTTP头信息的另一个特性,Yii提供了一系列的方法支持不同的文件发送需求。它们都内置支持HTTP范围内的头信息: yii\web\Response::sendFild(),发送一个已存在的文件到客户端 yii\web\Response::sendContentAsFile(),将一个文本字符串作为文件发送给客户端 yii\web\Response::sendStreamAsFile(),将一个已存在的文件流发送到客户端

这些方法有相同的特征:都以response对象作为返回值。如果要发送的文件非常大,你应该使用yii\web\Response::sendStreamAsFile(),因为它有更好的内存利用率。下例展示了如何在控制器的动作中发送一个文件:

public function actionDownload(){
	return \Yii::$app->response->sendFile('path/to/file.txt');
}

//实例: D:\phpwork\basic\controllers\ArticleController.php

public function actionView($id) {
	//文件a.php就被发送到客户端了!收到了!
	return Yii::$app->response->sendFile('D:\phpwork\basic\web\a.php');
	//发送服务器上任意文件到客户端!!跨站的a.php收到了!
	return Yii::$app->response->sendFile('D:\phpwork\advanced\a.php');
	//发送服务器上任意文件到客户端!!win.ini收到了!
	return Yii::$app->response->sendFile('C:\Windows\win.ini');
}

如果你在动作方法之外调用文件发送方法,你应该紧随调用yii\web\Response::send()方法以确保没有额外的内容被添加到response对象:

\Yii::$app->response->sendFile('path/to/file.txt')->send();

一些Web服务器有一个特定支持文件发送组件叫X-Sendfile,也就是将文件请求重定向到直接提供文件的Web服务器,因此,Web服务器发送文件时,Web应用就可以更早的结束服务了。要使用这个特性,你需要调用yii\web\Response::xSendFile(),以下列出了如何在一些流行的Web服务器上使用X-Sendfile特性生效: Apache:X-Sendfile Lighttpd v1.4:X-LIGHTTPD-send-file Lighttpd v1.5:X-Sendfile Nginx:X-Accel-Redirect Cherokee:X-Sendfile and X-Accel-Redirect

6、Sending Response(发送响应)

只有调用yii\web\Response::send()方法,响应内容才会被发送给用户。默认情况下,此方法将被yii\base\Application::run()自动调用。不管怎样,你也可以显式调用此方法强制立即发送响应。

yii\web\Response::send()方法按以下步骤发送响应: 1、触发yii\web\Response::EVENT_BEFORE_SEND事件 2、调用yii\web\Response::prepare()格式化响应的data为content 3、触发yii\web\Response::EVENT_AFTER_PREPARE事件 4、调用yii\web\Response::sendHeaders()发送注册的HTTP头信息 5、调用yii\web\Response::sendContent()发送响应的主体(body)信息 6、触发yii\web\Response::EVENT_AFTER_SEND事件

yii\web\Response::send()被调用一次后,此后对此方法的再次调用将被忽略,这意味着:响应一旦被发送,你将不能再向响应追加任何其他内容了。

如你所见,yii\web\Response::send()方法触发了几个有用的事件,通过应用这些事件,可以调整和修改响应。

(全文完)

    没有找到数据。
您需要登录后才可以回复。登录 | 立即注册