1. Requests
Request:
An application request is represented by a yiiwebRequest object, which provides information such as request parameters (Translator's Note: usually GET parameters or POST parameters), HTTP headers, cookies and other information. By default, for a given request, you can obtain access to the corresponding request object through the request application component application component (an instance of the yiiwebRequest class). In this chapter, we will introduce how to use this component in your application.
1. Request parameters
To get request parameters, you can call the yiiwebRequest::get() method and yiiwebRequest::post() method of the request component. They return the values of $_GET and $_POST respectively. For example,
$request = Yii::$app->request; $get = $request->get(); // 等价于: $get = $_GET; $id = $request->get('id'); // 等价于: $id = isset($_GET['id']) ? $_GET['id'] : null; $id = $request->get('id', 1); // 等价于: $id = isset($_GET['id']) ? $_GET['id'] : 1; $post = $request->post(); // 等价于: $post = $_POST; $name = $request->post('name'); // 等价于: $name = isset($_POST['name']) ? $_POST['name'] : null; $name = $request->post('name', ''); // 等价于: $name = isset($_POST['name']) ? $_POST['name'] : '';
Information: It is recommended that you obtain request parameters through the request component as above, instead of directly accessing $_GET and $_POST. This makes it easier for you to write test cases because you can fake data to create a mock request component.
When implementing RESTful APIs, you often need to obtain parameters submitted through PUT, PATCH or other request methods. You can get these parameters by calling the yiiwebRequest::getBodyParam() method. For example,
$request = Yii::$app->request; // 返回所有参数 $params = $request->bodyParams; // 返回参数 "id" $param = $request->getBodyParam('id');
Information: Unlike GET parameters, POST, PUT, PATCH, etc. submitted parameters are sent in the request body. When you access these parameters through the methods described above, the request component will parse these parameters. You can customize how these parameters are parsed by configuring the yiiwebRequest::parsers property.
2. Request method
You can get the HTTP method used by the current request through the Yii::$app->request->method expression. A set of Boolean attributes are also provided here to detect whether the current request is of a certain type. For example,
$request = Yii::$app->request; if ($request->isAjax) { /* 该请求是一个 AJAX 请求 */ } if ($request->isGet) { /* 请求方法是 GET */ } if ($request->isPost) { /* 请求方法是 POST */ } if ($request->isPut) { /* 请求方法是 PUT */ }
3. Request URLs
Therequest component provides many ways to detect the currently requested URL.
Assuming that the requested URL is http://example.com/admin/index.php/product?id=100, you can get the various parts of the URL as described below:
4.HTTP header
You can obtain HTTP header information through the yiiwebHeaderCollection returned by the yiiwebRequest::headers property. For example,
// $headers 是一个 yii\web\HeaderCollection 对象 $headers = Yii::$app->request->headers; // 返回 Accept header 值 $accept = $headers->get('Accept'); if ($headers->has('User-Agent')) { /* 这是一个 User-Agent 头 */ }
The request component also provides methods to quickly access common headers, including:
If your application supports multiple languages and you want to display the page in the end user's favorite language, then you can use the language negotiation method yiiwebRequest::getPreferredLanguage(). This method uses yiiwebRequest::acceptableLanguages to compare and filter the list of languages supported in your application and return the most suitable language.
Tip: You can also use the yiifiltersContentNegotiator filter to dynamically determine which content types and languages should be used in the response. This filter implements the content negotiation properties and methods described above.
5. Client information
You can obtain the host name and client IP address through yiiwebRequest::userHost and yiiwebRequest::userIP respectively, for example,
$userHost = Yii::$app->request->userHost; $userIP = Yii::$app->request->userIP;
二、响应(Responses)
响应:
当应用完成处理一个请求后, 会生成一个yii\web\Response响应对象并发送给终端用户 响应对象包含的信息有HTTP状态码,HTTP头和主体内容等, 网页应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。
在大多是情况下主要处理继承自 yii\web\Response 的 response 应用组件, 尽管如此,Yii也允许你创建你自己的响应对象并发送给终端用户,这方面后续会阐述。
在本节,将会描述如何构建响应和发送给终端用户。
1.状态码
构建响应时,最先应做的是标识请求是否成功处理的状态,可通过设置 yii\web\Response::statusCode 属性,该属性使用一个有效的HTTP 状态码。例如,为标识处理已被处理成功, 可设置状态码为200,如下所示:
Yii::$app->response->statusCode = 200;
尽管如此,大多数情况下不需要明确设置状态码,因为 yii\web\Response::statusCode 状态码默认为200, 如果需要指定请求失败,可抛出对应的HTTP异常,如下所示:
throw new \yii\web\NotFoundHttpException;
当错误处理器 捕获到一个异常,会从异常中提取状态码并赋值到响应, 对于上述的 yii\web\NotFoundHttpException 对应HTTP 404状态码,以下为Yii预定义的HTTP异常:
如果想抛出的异常不在如上列表中,可创建一个yii\web\HttpException异常,带上状态码抛出,如下:
throw new \yii\web\HttpException(402);
2.HTTP 头部
可在 response 组件中操控yii\web\Response::headers来发送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.响应主体
大多是响应应有一个主体存放你想要显示给终端用户的内容。
如果已有格式化好的主体字符串,可赋值到响应的yii\web\Response::content属性,例如:
Yii::$app->response->content = 'hello world!';
如果在发送给终端用户之前需要格式化,应设置 yii\web\Response::format 和 yii\web\Response::data 属性,yii\web\Response::format 属性指定yii\web\Response::data中数据格式化后的样式,例如:
$response = Yii::$app->response; $response->format = \yii\web\Response::FORMAT_JSON; $response->data = ['message' => 'hello world'];
Yii支持以下可直接使用的格式,每个实现了yii\web\ResponseFormatterInterface 类, 可自定义这些格式器或通过配置yii\web\Response::formatters 属性来增加格式器。
上述响应主体可明确地被设置,但是在大多数情况下是通过 操作 方法的返回值隐式地设置,常用场景如下所示:
public function actionIndex() { return $this->render('index'); }
上述的 index 操作返回 index 视图渲染结果,返回值会被 response 组件格式化后发送给终端用户。
因为响应格式默认为yii\web\Response::FORMAT_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, ], ]); }
注意: 如果创建你自己的响应对象,将不能在应用配置中设置 response 组件,尽管如此, 可使用 依赖注入 应用通用配置到你新的响应对象。
4.浏览器跳转
浏览器跳转依赖于发送一个Location HTTP 头,因为该功能通常被使用,Yii提供对它提供了特别的支持。
可调用yii\web\Response::redirect() 方法将用户浏览器跳转到一个URL地址,该方法设置合适的 带指定URL的 Location 头并返回它自己为响应对象,在操作的方法中,可调用缩写版yii\web\Controller::redirect(),例如:
public function actionOld() { return $this->redirect('http://example.com/new', 301); }
在如上代码中,操作的方法返回redirect() 方法的结果,如前所述,操作的方法返回的响应对象会被当总响应发送给终端用户。
除了操作方法外,可直接调用yii\web\Response::redirect() 再调用 yii\web\Response::send() 方法来确保没有其他内容追加到响应中。
\Yii::$app->response->redirect('http://example.com/new', 301)->send();
补充: yii\web\Response::redirect() 方法默认会设置响应状态码为302,该状态码会告诉浏览器请求的资源 临时 放在另一个URI地址上,可传递一个301状态码告知浏览器请求的资源已经 永久 重定向到新的URId地址。
如果当前请求为AJAX 请求,发送一个 Location 头不会自动使浏览器跳转,为解决这个问题, yii\web\Response::redirect() 方法设置一个值为要跳转的URL的X-Redirect 头, 在客户端可编写JavaScript 代码读取该头部值然后让浏览器跳转对应的URL。
补充: Yii 配备了一个yii.js JavaScript 文件提供常用JavaScript功能,包括基于X-Redirect头的浏览器跳转, 因此,如果你使用该JavaScript 文件(通过yii\web\YiiAsset 资源包注册),就不需要编写AJAX跳转的代码。
5.发送文件
和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能,Yii提供方法集合来支持各种文件发送需求,它们对HTTP头都有内置的支持。
这些方法都将响应对象作为返回值,如果要发送的文件非常大,应考虑使用 yii\web\Response::sendStreamAsFile() 因为它更节约内存,以下示例显示在控制器操作中如何发送文件:
public function actionDownload() { return \Yii::$app->response->sendFile('path/to/file.txt'); }
如果不是在操作方法中调用文件发送方法,在后面还应调用 yii\web\Response::send() 没有其他内容追加到响应中。
\Yii::$app->response->sendFile('path/to/file.txt')->send();
一些浏览器提供特殊的名为X-Sendfile的文件发送功能,原理为将请求跳转到服务器上的文件, 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.发送响应
在yii\web\Response::send() 方法调用前响应中的内容不会发送给用户,该方法默认在yii\base\Application::run() 结尾自动调用,尽管如此,可以明确调用该方法强制立即发送响应。
yii\web\Response::send() 方法使用以下步骤来发送响应:
一旦yii\web\Response::send() 方法被执行后,其他地方调用该方法会被忽略, 这意味着一旦响应发出后,就不能再追加其他内容。
如你所见yii\web\Response::send() 触发了几个实用的事件,通过响应这些事件可调整或包装响应。