Commit 29a5cd20 by Qiang Xue

more guide.

parent e305f084
...@@ -49,9 +49,9 @@ Handling Requests ...@@ -49,9 +49,9 @@ Handling Requests
* [Overview](runtime-overview.md) * [Overview](runtime-overview.md)
* [Bootstrapping](runtime-bootstrapping.md) * [Bootstrapping](runtime-bootstrapping.md)
* **TBD** [Routing](runtime-routing.md) * [Routing](runtime-routing.md)
* **TBD** [Requests](runtime-requests.md) * [Requests](runtime-requests.md)
* **TBD** [Responses](runtime-responses.md) * [Responses](runtime-responses.md)
* **TBD** [Sessions and Cookies](runtime-sessions-cookies.md) * **TBD** [Sessions and Cookies](runtime-sessions-cookies.md)
* [URL Parsing and Generation](runtime-url-handling.md) * [URL Parsing and Generation](runtime-url-handling.md)
* [Handling Errors](runtime-handling-errors.md) * [Handling Errors](runtime-handling-errors.md)
...@@ -152,7 +152,7 @@ Testing ...@@ -152,7 +152,7 @@ Testing
------- -------
* [Overview](test-overview.md) * [Overview](test-overview.md)
* [Testing environment setup](test-endvironment-setup.md) * [Testing environment setup](test-environment-setup.md)
* [Unit Tests](test-unit.md) * [Unit Tests](test-unit.md)
* [Functional Tests](test-functional.md) * [Functional Tests](test-functional.md)
* [Acceptance Tests](test-acceptance.md) * [Acceptance Tests](test-acceptance.md)
......
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;
```
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.
...@@ -28,8 +28,8 @@ structure-extensions.md | Yes ...@@ -28,8 +28,8 @@ structure-extensions.md | Yes
runtime-overview.md | Yes runtime-overview.md | Yes
runtime-bootstrapping.md | Yes runtime-bootstrapping.md | Yes
runtime-routing.md | Yes runtime-routing.md | Yes
runtime-requests.md | runtime-requests.md | Yes
runtime-responses.md | runtime-responses.md | Yes
runtime-sessions-cookies.md | runtime-sessions-cookies.md |
runtime-url-handling.md | runtime-url-handling.md |
runtime-handling-errors.md | runtime-handling-errors.md |
......
...@@ -142,7 +142,7 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces ...@@ -142,7 +142,7 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces
/** /**
* Removes a header. * Removes a header.
* @param string $name the name of the header to be removed. * @param string $name the name of the header to be removed.
* @return string the value of the removed header. Null is returned if the header does not exist. * @return array the value of the removed header. Null is returned if the header does not exist.
*/ */
public function remove($name) public function remove($name)
{ {
...@@ -150,7 +150,6 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces ...@@ -150,7 +150,6 @@ class HeaderCollection extends Object implements \IteratorAggregate, \ArrayAcces
if (isset($this->_headers[$name])) { if (isset($this->_headers[$name])) {
$value = $this->_headers[$name]; $value = $this->_headers[$name];
unset($this->_headers[$name]); unset($this->_headers[$name]);
return $value; return $value;
} else { } else {
return null; return null;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment