Qiang Xue
10 years ago
5 changed files with 404 additions and 8 deletions
@ -0,0 +1,139 @@
|
||||
Requests |
||||
======== |
||||
|
||||
Requests made to an application are represented in terms of [[yii\web\Request]] objects which provide information |
||||
such as request parameters, HTTP headers, cookies, etc. For a given request, you can get access to the corresponding |
||||
request object via the `request` [application component](structure-application-components.md). In this section, |
||||
we will describe how you can make use of this component in your applications. |
||||
|
||||
|
||||
## Request Parameters <a name="request-parameters"></a> |
||||
|
||||
To get request parameters, you can call [[yii\web\Request::get()|get()]] and [[yii\web\Request::post()|post()]] methods |
||||
of the `request` component. They return the values of `$_GET` and `$_POST`, respectively. For example, |
||||
|
||||
```php |
||||
$request = Yii::$app->request; |
||||
|
||||
$get = $request->get(); |
||||
// equivalent to: $get = $_GET; |
||||
|
||||
$id = $request->get('id'); |
||||
// equivalent to: $id = isset($_GET['id']) ? $_GET['id'] : null; |
||||
|
||||
$id = $request->get('id', 1); |
||||
// equivalent to: $id = isset($_GET['id']) ? $_GET['id'] : 1; |
||||
|
||||
$post = $request->post(); |
||||
// equivalent to: $post = $_POST; |
||||
|
||||
$name = $request->post('name'); |
||||
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : null; |
||||
|
||||
$name = $request->post('name', ''); |
||||
// equivalent to: $name = isset($_POST['name']) ? $_POST['name'] : ''; |
||||
``` |
||||
|
||||
> Info: Instead of directly accessing `$_GET` and `$_POST` to retrieve the request parameters, it is recommended |
||||
that you get them via the `request` component like shown above. This will make writing tests easier because |
||||
you can create a mock request component with faked request data. |
||||
|
||||
When implementing [RESTful APIs](rest-quick-start.md), you often need to retrieve parameters that are submitted |
||||
via PUT, PATCH or other [request methods](#request-methods). You can get these parameters by calling |
||||
the [[yii\web\Request::getBodyParam()]] methods. For example, |
||||
|
||||
```php |
||||
$request = Yii::$app->request; |
||||
|
||||
// returns all parameters |
||||
$params = $request->bodyParams; |
||||
|
||||
// returns the parameter "id" |
||||
$param = $request->getBodyParam('id'); |
||||
``` |
||||
|
||||
> Info: Unlike `GET` parameters, parameters submitted via `POST`, `PUT`, `PATCH` etc. are sent in the request body. |
||||
The `request` component will parse these parameters when you access them through the methods described above. |
||||
You can customize the way how these parameters are parsed by configuring the [[yii\web\Request::parsers]] property. |
||||
|
||||
|
||||
## Request Methods <a name="request-methods"></a> |
||||
|
||||
You can get the HTTP method used by the current request via the expression `Yii::$app->request->method`. |
||||
A whole set of boolean properties are also provided for you to check if the current method is of certain type. |
||||
For example, |
||||
|
||||
```php |
||||
$request = Yii::$app->request; |
||||
|
||||
if ($request->isAjax) { // the request is an AJAX request } |
||||
if ($request->isGet) { // the request method is GET } |
||||
if ($request->isPost) { // the request method is POST } |
||||
if ($request->isPut) { // the request method is PUT } |
||||
``` |
||||
|
||||
## Request URLs <a name="request-urls"></a> |
||||
|
||||
The `request` component provides many ways of inspecting the currently requested URL. |
||||
|
||||
Assuming the URL being requested is `http://example.com/admin/index.php/product?id=100`, you can get various |
||||
parts of this URL as summarized in the following: |
||||
|
||||
* [[yii\web\Request::url|url]]: returns `/admin/index.php/product?id=100`, which is the URL without the host info part. |
||||
* [[yii\web\Request::absoluteUrl|absoluteUrl]]: returns `http://example.com/admin/index.php/product?id=100`, |
||||
which is the whole URL including the host info part. |
||||
* [[yii\web\Request::hostInfo|hostInfo]]: returns `http://example.com`, which is the host info part of the URL. |
||||
* [[yii\web\Request::pathInfo|pathInfo]]: returns `/product`, which is the part after the entry script and |
||||
before the question mark (query string). |
||||
* [[yii\web\Request::queryString|queryString]]: returns `id=100`, which is the part after the question mark. |
||||
* [[yii\web\Request::baseUrl|baseUrl]]: returns `/admin`, which is the part after the host info and before |
||||
the entry script name. |
||||
* [[yii\web\Request::scriptUrl|scriptUrl]]: returns `/admin/index.php`, which is the URL without path info and query string. |
||||
* [[yii\web\Request::serverName|serverName]]: returns `example.com`, which is the host name in the URL. |
||||
* [[yii\web\Request::serverPort|serverPort]]: returns 80, which is the port used by the Web server. |
||||
|
||||
|
||||
## HTTP Headers <a name="http-headers"></a> |
||||
|
||||
You can get the HTTP header information through the [[yii\web\HeaderCollection|header collection]] returned |
||||
by the [[yii\web\Request::headers]] property. For example, |
||||
|
||||
```php |
||||
// $headers is an object of yii\web\HeaderCollection |
||||
$headers = Yii::$app->request->headers; |
||||
|
||||
// returns the Accept header value |
||||
$accept = $headers->get('Accept'); |
||||
|
||||
if ($headers->has('User-Agent')) { // there is User-Agent header } |
||||
``` |
||||
|
||||
The `request` component also provides support for quickly accessing some commonly used headers, including |
||||
|
||||
* [[yii\web\Request::userAgent|userAgent]]: returns the value of the `User-Agent` header. |
||||
* [[yii\web\Request::contentType|contentType]]: returns the value of the `Content-Type` header which indicates |
||||
the MIME type of the data in the request body. |
||||
* [[yii\web\Request::acceptableContentTypes|acceptableContentTypes]]: returns the content MIME types acceptable by users. |
||||
The returned types ordered by the quality score. Types with the highest scores will be returned first. |
||||
* [[yii\web\Request::acceptableLanguages|acceptableLanguages]]: returns the languages acceptable by users. |
||||
The returned languages are ordered by their preference level. The first element represents the most preferred language. |
||||
|
||||
If your application supports multiple languages and you want to display pages in the language that is the most preferred |
||||
by the end user, you may use the language negotiation method [[yii\web\Request::getPreferredLanguage()]]. |
||||
This method takes a list of languages supported by your application, compares them with [[yii\web\Request::acceptableLanguages|acceptableLanguages]], |
||||
and returns the most appropriate language. |
||||
|
||||
> Tip: You may also use the [[yii\filters\ContentNegotiator|ContentNegotiator]] filter to dynamically determine |
||||
what content type and language should be used in the response. The filter implements the content negotiation |
||||
on top the properties and methods described above. |
||||
|
||||
|
||||
## Client Information <a name="client-information"></a> |
||||
|
||||
You can get the host name and IP address of the client machine through [[yii\web\Request::userHost|userHost]] |
||||
and [[yii\web\Request::userIP|userIP]], respectively. For example, |
||||
|
||||
```php |
||||
$userHost = Yii::$app->request->userHost; |
||||
$userIP = Yii::$app->request->userIP; |
||||
``` |
@ -0,0 +1,258 @@
|
||||
Responses |
||||
========= |
||||
|
||||
When an application finishes handling a [request](runtime-requests.md), it generates a [[yii\web\Response|response]] object |
||||
and sends it to the end user. The response object contains information such as the HTTP status code, HTTP headers and body. |
||||
The ultimate goal of Web application development is essentially to build such response objects upon various requests. |
||||
|
||||
In most cases you should mainly deal with the `response` [application component](structure-application-components.md). |
||||
However, Yii also allows you to create your own response objects and send them to end users. |
||||
|
||||
In this section, we will describe how to compose and send responses to end users. |
||||
|
||||
|
||||
## Status Code <a name="status-code"></a> |
||||
|
||||
One of the first things you would do when building a response is to state whether the request is successfully handled. |
||||
This is done by setting the [[yii\web\Response::statusCode]] property which can take one of the valid |
||||
[HTTP status codes](http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html). For example, to indicate the request |
||||
is successfully handled, you may set the status code to be 200, like the following: |
||||
|
||||
```php |
||||
Yii::$app->response->statusCode = 200; |
||||
``` |
||||
|
||||
However, in most cases you do not need to explicitly set the status code. This is because the default value |
||||
of [[yii\web\Response::statusCode]] is 200. And if you want to indicate the request is unsuccessful, you may |
||||
throw an appropriate HTTP exception like the following: |
||||
|
||||
```php |
||||
throw new \yii\web\NotFoundHttpException; |
||||
``` |
||||
|
||||
When the [error handler](runtime-handling-errors.md) catches an exception, it will extract the status code |
||||
from the exception and assign it to the response. For the [[yii\web\NotFoundHttpException]] above, it is |
||||
associated with the HTTP status 404. The following HTTP exceptions are predefined in Yii: |
||||
|
||||
* [[yi\web\BadRequestHttpException]]: status code 400. |
||||
* [[yi\web\ConflictHttpException]]: status code 409. |
||||
* [[yi\web\ForbiddenHttpException]]: status code 403. |
||||
* [[yi\web\GoneHttpException]]: status code 410. |
||||
* [[yi\web\MethodNotAllowedHttpException]]: status code 405. |
||||
* [[yi\web\NotAcceptableHttpException]]: status code 406. |
||||
* [[yi\web\NotFoundHttpException]]: status code 404. |
||||
* [[yi\web\ServerErrorHttpException]]: status code 500. |
||||
* [[yi\web\TooManyRequestsHttpException]]: status code 429. |
||||
* [[yi\web\UnauthorizedHttpException]]: status code 401. |
||||
* [[yi\web\UnsupportedMediaTypeHttpException]]: status code 415. |
||||
|
||||
If the exception that you want to throw is not among the above list, you may create one by extending |
||||
from [[yii\web\HttpException]], or directly throw it with a status code, for example, |
||||
|
||||
```php |
||||
throw new \yii\web\HttpException(402); |
||||
``` |
||||
|
||||
|
||||
## HTTP Headers <a name="http-headers"></a> |
||||
|
||||
You can send HTTP headers by manipulating the [[yii\web\Response::headers|header collection]] in the `response` component. |
||||
For example, |
||||
|
||||
```php |
||||
$headers = Yii::$app->response->headers; |
||||
|
||||
// add a Pragma header. Existing Pragma headers will NOT be overwritten. |
||||
$headers->add('Pragma', 'no-cache'); |
||||
|
||||
// set a Pragma header. Any existing Pragma headers will be discarded. |
||||
$headers->add('Pragma', 'no-cache'); |
||||
|
||||
// remove Pragma header(s) and return the removed Pragma header values in array |
||||
$values = $headers->remove('Pragma'); |
||||
``` |
||||
|
||||
> Info: Header names are case insensitive. And the newly registered headers are not sent to the user until |
||||
the [[yii\web\Response::send()]] method is called. |
||||
|
||||
|
||||
## Response Body <a name="response-body"></a> |
||||
|
||||
Most responses should have a body which gives the content that you want to show to end users. |
||||
|
||||
If you already have a formatted body string, you may assign it to the [[yii\web\Response::content]] property |
||||
of the response. For example, |
||||
|
||||
```php |
||||
Yii::$app->request->content = 'hello world!'; |
||||
``` |
||||
|
||||
If you data needs to be formatted before sending to end users, you should set both of the |
||||
[[yii\web\Response::format|format]] and [[yii\web\Response::data|data]] properties. The [[yii\web\Response::format|format]] |
||||
property specifies in which format should the [[yii\web\Response::data|data]] be formatted as. For example, |
||||
|
||||
```php |
||||
$response = Yii::$app->request; |
||||
$response->format = \yii\web\Response::FORMAT_JSON; |
||||
$response->data = ['message' => 'hello world']; |
||||
``` |
||||
|
||||
Yii supports the following formats out of box, each implemented by a [[yii\web\ResponseFormatterInterface|formatter]] class. |
||||
You can customize these formatters or add new ones by configuring the [[yii\web\Response::formatters]] property. |
||||
|
||||
* [[yii\web\Response::FORMAT_HTML|HTML]]: implemented by [[yii\web\HtmlResponseFormatter]]. |
||||
* [[yii\web\Response::FORMAT_XML|XML]]: implemented by [[yii\web\XmlResponseFormatter]]. |
||||
* [[yii\web\Response::FORMAT_JSON|JSON]]: implemented by [[yii\web\JsonResponseFormatter]]. |
||||
* [[yii\web\Response::FORMAT_JSONP|JSONP]]: implemented by [[yii\web\JsonResponseFormatter]]. |
||||
|
||||
While response body can be set explicitly as shown above, in most cases you may set it implicitly by the return value |
||||
of [action](structure-controllers.md) methods. A common use case is like the following: |
||||
|
||||
```php |
||||
public function actionIndex() |
||||
{ |
||||
return $this->render('index'); |
||||
} |
||||
``` |
||||
|
||||
The `index` action above returns the rendering result of the `index` view. The return value will be taken |
||||
by the `response` component, formatted and then sent to end users. |
||||
|
||||
Because by default, the response format is as [[yii\web\Response::FORMAT_HTML|HTML]], you should only return a string |
||||
in an action method. If you want to use a different response format, you should set it first before returning the data. |
||||
For example, |
||||
|
||||
```php |
||||
public function actionInfo() |
||||
{ |
||||
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; |
||||
return [ |
||||
'message' => 'hello world', |
||||
'code' => 100, |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
As aforementioned, besides using the default `response` application component, you can also create your own |
||||
response objects and send them to end users. You can do so by returning such an object in an action method, like the following, |
||||
|
||||
```php |
||||
public function actionInfo() |
||||
{ |
||||
return \Yii::createObject([ |
||||
'class' => 'yii\web\Response', |
||||
'format' => \yii\web\Response::FORMAT_JSON, |
||||
'data' => [ |
||||
'message' => 'hello world', |
||||
'code' => 100, |
||||
], |
||||
]); |
||||
} |
||||
``` |
||||
|
||||
> Note: If you are creating your own response objects, you will not be able to take advantage of the configurations |
||||
that you set for the `response` component in the application configuration. You can, however, use |
||||
[dependency injection](concept-di-container.md) to apply common configuration to your new response objects. |
||||
|
||||
|
||||
## Browser Redirection <a name="browser-redirection"></a> |
||||
|
||||
Browser redirection relies on sending a `Location` HTTP header. Because this feature is commonly used, Yii provides |
||||
some special supports for it. |
||||
|
||||
You can redirect the user browser to a URL by calling the [[yii\web\Response::redirect()]] method. The method |
||||
sets the appropriate `Location` header with the given URL and returns the response object itself. In an action method, |
||||
you can call its shortcut version [[yii\web\Controller::redirect()]]. For example, |
||||
|
||||
```php |
||||
public function actionOld() |
||||
{ |
||||
return $this->redirect('http://example.com/new', 301); |
||||
} |
||||
``` |
||||
|
||||
In the above code, the action method returns the result of the `redirect()` method. As explained before, the response |
||||
object returned by an action method will be used as the response sending to end users. |
||||
|
||||
In places other than an action method, you should call [[yii\web\Response::redirect()]] directly followed by |
||||
a call to the [[yii\web\Response::send()]] method to ensure no extra content will be appended to the response. |
||||
|
||||
```php |
||||
\Yii::$app->response->redirect('http://example.com/new', 301)->send(); |
||||
``` |
||||
|
||||
> Info: By default, the [[yii\web\Response::redirect()]] method sets the response status code to be 302 which instructs |
||||
the browser that the resource being requested is *temporarily* located in a different URI. You can pass in a status |
||||
code 301 to tell the browser that the resource has been *permanently* relocated. |
||||
|
||||
When the current request is an AJAX request, sending a `Location` header will not automatically cause the browser |
||||
redirection. To solve this problem, the [[yii\web\Response::redirect()]] method sets an `X-Redirect` header with |
||||
the redirection URL as its value. On the client side you may write JavaScript code to read this header value and |
||||
redirect the browser accordingly. |
||||
|
||||
> Info: Yii comes with a `yii.js` JavaScript file which provides a set of commonly used JavaScript utilities, |
||||
including browser redirection based on the `X-Redirect` header. Therefore, if you are using this JavaScript file |
||||
(by registering the [[yii\web\YiiAsset]] asset bundle), you do not need to write anything to support AJAX redirection. |
||||
|
||||
|
||||
## Sending Files <a name="sending-files"></a> |
||||
|
||||
Like browser redirection, file sending is another feature that relies on specific HTTP headers. Yii provides |
||||
a set of methods to support various file sending needs. They all have built-in support for HTTP range header. |
||||
|
||||
* [[yii\web\Response::sendFile()]]: sends an existing file to client. |
||||
* [[yii\web\Response::sendContentAsFile()]]: sends a text string as a file to client. |
||||
* [[yii\web\Response::sendStreamAsFile()]]: sends an existing file stream as a file to client. |
||||
|
||||
These methods have the same method signature with the response object as the return value. If the file |
||||
to be sent is very big, you should consider using [[yii\web\Response::sendStreamAsFile()]] because it is more |
||||
memory efficient. The following example shows how to send a file in a controller action: |
||||
|
||||
```php |
||||
public function actionDownload() |
||||
{ |
||||
return \Yii::$app->response->sendFile('path/to/file.txt'); |
||||
} |
||||
``` |
||||
|
||||
If you are calling the file sending method in places other than an action method, you should also call |
||||
the [[yii\web\Response::send()]] method afterwards to ensure no extra content will be appended to the response. |
||||
|
||||
```php |
||||
\Yii::$app->response->sendFile('path/to/file.txt')->send(); |
||||
``` |
||||
|
||||
Some Web servers have a special file sending support called *X-Sendfile*. The idea is to redirect the |
||||
request for a file to the Web server which will directly serve the file. As a result, the Web application |
||||
can terminate earlier while the Web server is sending the file. To use this feature, you may call |
||||
the [[yii\web\Response::xSendFile()]]. The following list summarizes how to enable the `X-Sendfile` feature |
||||
for some popular Web servers: |
||||
|
||||
- Apache: [X-Sendfile](http://tn123.org/mod_xsendfile) |
||||
- Lighttpd v1.4: [X-LIGHTTPD-send-file](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) |
||||
- Lighttpd v1.5: [X-Sendfile](http://redmine.lighttpd.net/projects/lighttpd/wiki/X-LIGHTTPD-send-file) |
||||
- Nginx: [X-Accel-Redirect](http://wiki.nginx.org/XSendfile) |
||||
- Cherokee: [X-Sendfile and X-Accel-Redirect](http://www.cherokee-project.com/doc/other_goodies.html#x-sendfile) |
||||
|
||||
|
||||
## Sending Response <a name="sending-response"></a> |
||||
|
||||
The content in a response is not sent to the user until the [[yii\web\Response::send()]] method is called. |
||||
By default, this method will be called automatically at the end of [[yii\base\Application::run()]]. You can, however, |
||||
explicitly call this method to force sending out the response immediately. |
||||
|
||||
The [[yii\web\Response::send()]] method takes the following steps to send out a response: |
||||
|
||||
1. Trigger the [[yii\web\Response::EVENT_BEFORE_SEND]] event. |
||||
2. Call [[yii\web\Response::prepare()]] to format [[yii\web\Response::data|response data]] into |
||||
[[yii\web\Response::content|response content]]. |
||||
3. Trigger the [[yii\web\Response::EVENT_AFTER_PREPARE]] event. |
||||
4. Call [[yii\web\Response::sendHeaders()]] to send out the registered HTTP headers. |
||||
5. Call [[yii\web\Response::sendContent()]] to send out the response body content. |
||||
6. Trigger the [[yii\web\Response::EVENT_AFTER_SEND]] event. |
||||
|
||||
After the [[yii\web\Response::send()]] method is called once, any further call to this method will be ignored. |
||||
This means once the response is sent out, you will not be able to append more content to it. |
||||
|
||||
As you can see, the [[yii\web\Response::send()]] method triggers several useful events. By responding to |
||||
these events, it is possible to adjust or decorate the response. |
Loading…
Reference in new issue