yii2-response

https://www.yiiframework.com/doc/guide/2.0/en/runtime-responses

当应用处理完一个 request,它会生成一个 yii\web\Response object and send it to the end user。response 对象包含了以下信息:

  • HTTP status code
    • Yii::$app->response->statusCode = 200;
    • throw new \yii\web\NotFoundHttpException;
  • HTTP Headers
    • 可以使用 Yii::$app->response->headers 的三个方法 add set remove
  • HTTP Body
    • 如果你的数据已经格式化好了,可以直接赋值 Yii::$app->response->content = 'hello';
    • 如果你的数据需要格式化,则需要同时设置 Yii::$app->response->dataYii::$app->response->format

尽管 Response 可以像上面那样显式赋值,但是,大多数情况下我们是通过 return value of action methods 来赋值的。例如:

public funtion actionIndex()
{
    // 相当于 Yii::$app->response->data = $this->render('index')
    return $this->render('index');
}

The index action 的返回值被 response 组件接收,格式化,再发送到 end users。

因为 response format 的默认值是 yii\web\Response::FORMAT_HTML,所以我们在 action method 中只需要 return a string。就是将 string 格式化为 html。

如果需要返回 json,则 yii\web\Response::$data 应该为一个 array:

public funtion actionIndex()
{
    Yii::$app->response->format = yii\web\Response::FORMAT_JSON;
    
    // 相当于 Yii::$app->response->data = ['message' => 'hello', 'code' => 100 ]
    return ['message' => 'hello', 'code' => 100 ];
}

浏览器重定向

yii\web\Response::redirect() 方法会设置 Location header 然后 return the object self。

public funtion actionOld()
{
    return $this->redirect('http://example.com/new', 301);
}
  • action 方法中返回的 response 对象会被 response 组件发送给用户。
  • action 方法之外的地方需要链式调用 \Yii::$app->response->redirect('http://example.com/new', 301)->send()

如果是 Ajax 请求,发送 Location header 是不会让浏览器跳转的。解决方法是发送 X-Redirect header,在客户端上,你需要 JavaScript 代码来读取 X-Redirect header 然后重定向。

格式化

yii\web\Response::$data 经过 yii\web\Response::$format 格式化为 yii\web\Response::$content

action 的返回值不能是 array,否则会报错 Invalid Argument – yii\base\InvalidArgumentException

发送响应

yii\web\Response::send() 方法调用前响应中的内容不会发送给用户, 该方法默认在yii\base\Application::run() 结尾自动调用,尽管如此,可以明确调用该方法强制立即发送响应。

yii\web\Response::send() 方法使用以下步骤来发送响应:

  • 触发 yii\web\Response::EVENT_BEFORE_SEND 事件.
  • 调用 yii\web\Response::prepare() 来格式化 response data 为 response content.
  • 触发 yii\web\Response::EVENT_AFTER_PREPARE 事件.
  • 调用 yii\web\Response::sendHeaders() 来发送注册的HTTP头,并且调用 yii\web\Response::sendHeaders()
  • 调用 yii\web\Response::sendContent() 来发送响应主体内容
  • 触发 yii\web\Response::EVENT_AFTER_SEND 事件.

一旦yii\web\Response::send() 方法被执行后,其他地方调用该方法会被忽略,这意味着一旦响应发出后,就不能再追加其他内容。

如你所见yii\web\Response::send() 触发了几个实用的事件, 通过响应这些事件可调整或包装响应。

PHP 基础

发送响应的流程:

  1. header() — 发送原生 HTTP 头
  2. setcookie() - 发送 Cookie
  3. echo $this->content;
  4. return

另外可以在 调用 header() 发送 HTTP Headers 之前,使用 headers_sent() 检测 HTTP 头是否已经发送。如果已经发送则抛异常 yii\web\HeadersAlreadySentException