【Yii系列】处理请求

缘起

这一章是Yii系列的第三章,前两章给大伙讲解了Yii2.0的安装与Yii2.0的基本框架及基础概念,传送门:php

【Yii2.0的安装与调试】:http://www.cnblogs.com/riverdubu/p/6439680.htmlhtml

【Yii2.0基础框架】:http://www.cnblogs.com/riverdubu/p/6607373.html前端

相信学习过上两章的内容,大家是否是对Yii有个大体的了解了呢,Yii2.0基础框架这一章很重要,不只仅是由于它的长度,而是里面讲解了整个Yii2.0的基础概念,以及如何基于MVC模型构建的它的整套框架,只是浮于表面的一些基础只是,若是你们对更深层次的Yii的底层感兴趣,能够持续关注个人博客,后面我会对于Yii底层的一些关键组件和代码作更加详细的讲解。react

接上一章的话,咱们这章带大伙了解下一个用户的请求从发起到收到响应的整个过程是如何实现,这对于统筹全局相当重要,若是说上一章是基础,是打根基和搭架子的一章,那么这一章就是给你将整个房子建起来啦,会把全部的门窗房间规划好,让你可以轻松自如的在房子里面穿梭。git

运行机制

首先,咱们来看下整个请求的运行机制web

用户发送请求给入口脚本,入口脚本加载配置,运行application,application会建立一个request组件去处理此次用户请求,Request组件会去路由里面查找用户想要请求的那个Controller,找到Controller后实例化它,调用对应的action执行操做,action会调用对应model层的函数进行数据处理,处理完成以后返回给对应的action,action会将数据格式化或者不格式化渲染View,为其提供填充所须要的数据,渲染完成的结果会返回给response组件发送给用户浏览器。json

这里面有几个关键的组件,request和response咱们先不用去管他们,这是application会自动搞定的,咱们要关心关心这个被称为路由的东西。后端

路由

有几个关键概念是须要你们理解下的,引导路由。api

当入口脚本在调用 yii\web\Application::run() 方法时,它进行的第一个操做就是解析输入的请求,而后实例化对应的Controller处理这个请求。 该过程就被称为引导路由(routing)数组

咱们以前可能看过相似于下面的请求URL

http://服务器IP/index.php?r=post/view&id=100

这边的r后面的就是后面会被实例化的Controller去处理此次请求,这是标准的写法,可是,为了让URL看上去更pretty一些,比方说下面的URL

http://服务器IP/post/view?id=100

这样是否是可以更清晰的看出是哪一个业务单元的逻辑,这样的写法须要经过配置应用主体Components中一个叫urlManager的配置项来完成路由的解析。

这两种写法之间经过配置urlManager里面的enablePrettyUrl属性来实现切换,true的话是下面一种写法,false的话是上面一种写法。

引导路由包含两步,第一步,请求会被解析成对应的路由和请求参数,第二步,一个路由对应的Controller的action会被实例化去处理这个请求。

当你使用pretty方式去解析你的URL时,urlManager会在当前的规则中寻找你想要找的规则,若是找不到,会抛出一个 yii\web\NotFoundHttpException,这就是大名鼎鼎的404啦。

一旦找到对应的路由规则,URL会被拆分红不少部分,就像上面的post/view同样,从前日后可能分别对应了一个module,一个controller,一个action。application回一个个去尝试的,若是没有找到对应的action去执行这个请求,仍是会像上面同样,抛出大名鼎鼎的404。

咱们这边对基础的路由不作解析,想要了解的朋友能够去官网详细的查看下。咱们来具体的来看下pretty的路由规则。

为了可以使用pretty路由解析,咱们得在应用主体,也就是上一章的web.php中配置一下。

[
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,
            'showScriptName' => false,
            'enableStrictParsing' => false,
            'rules' => [
                // ...
            ],
        ],
    ],
]

具体的规则就要配置在rules,这里建议一下,这个rules配置在一个文件中,而后这边require一下便可。

这里面有几个参数

enablePrettyUrl:和上面的意思同样,打开pretty url规则的,这个必须得打开,要否则的话默认的路由解析会是基础路由解析。

showScriptName:是否将入口脚本写入用户请求的连接,若是为true,请求连接为:/index.php/post/100,若是为false,请求连接为:/post/100

enableStrictParsing:是否须要按照rules里的规则严格解析,若是为true,请求的连接必须符合rules里面的规则,若是不知足,抛出404,若是为false,请求连接能够是rules规则的一部分。

url rules

下面咱们就来详细的讲一讲须要配置的这个rules文件。

咱们先来看个例子

[
    'posts' => 'post/index', 
    'post/<id:\d+>' => 'post/view',
]

这边定义了两条URL rules

第一条将URL中的posts对应到post/index这条路由;

第二条规则匹配一个正则式post/(\d+)对应到post/view这条路由,id是它的参数。

当URL被规则解析,他后面的参数会被收录进application的request组件,后面咱们会说到这个request组件。在我看来,处女座的人比较满意的一个url是这样的:http://example.com/psot/action?a=1&b=2,这是比较常规的

我这边给出的一个例子适用于大多数状况

'v1/<module:\w+>/<controller:\w+>/<action:\w+>' => 'api/v1/<module>/<controller>/<action>', //模块相关规则

前面部分是用户访问时的连接格式,后面部分是项目代码中对应的action位置。

经过正则式去解析路由,这回大大减小规则数量,大大提高urlManager的性能。

Request 

讲完了路由,咱们再来看下一个请求是如何被应用主体接受和反馈的吧。

首先,咱们来看下在应用中,用户的请求是被实例化成啥的。

一个应用的请求是用 yii\web\Request 对象来表示的,该对象提供了诸如 请求参数(译者注:一般是GET参数或者POST参数)、HTTP头、cookies等信息。

调用方式

Yii::$app->request

$request->get()这段代码等价于$_GET,以前和大伙说过,不能直接使用$_GET这个值,这使你更容易编写测试用例,由于你能够伪造数据来建立一个模拟请求组件。

你能够经过 Yii::$app->request->method 表达式来获取当前请求使用的HTTP方法。

$request = Yii::$app->request;

if ($request->isAjax) { /* 该请求是一个 AJAX 请求 */ }
if ($request->isGet)  { /* 请求方法是 GET */ }
if ($request->isPost) { /* 请求方法是 POST */ }
if ($request->isPut)  { /* 请求方法是 PUT */ }

我这边通常的是使用一个Web基类去获取请求的body和head

$requestBody = $this->getParam('body');
$requestHeader = $this->getParam('header');

Web基类

<?php
namespace ext\controller;

use Yii;
use yii\web\Controller;

class Web extends Controller
{
    public function init()
    {
        parent::init();
        $this->setDefaultCrumbs();
    }

    public function beforeaction($action)
    {
        return parent::beforeaction($action);
    }

    ......

    /**
     * 获取参数
     * @param null $key
     * @param null $val
     * @return array|mixed|null
     */
    public function getParam($key = null, $val = null)
    {

        $request = Yii::$app->request;

        $data = [];
        /**
         * 若是是GET请求
         */
        if ($request->getIsGet()) {
            $data = $request->get('request');
        } elseif ($request->getIsPost()) {
            if($request->contentType == 'application/json')
            {
                $rawBody = $request->rawBody;
                if($rawBody){
                    $requestData = json_decode($rawBody,true);
                    $data = $requestData['request'];
                    unset($requestData);
                }
            }else{
                $data = $request->post('request');
            }
        } elseif ($request->getIsDelete()) {
            $data = $request->get('request');
        }

        if (isset($data[$key])) {
            if (is_null($data[$key])) {
                return $val;
            } else {
                return $data[$key];
            }
        } elseif (is_null($key)) {
            return $data;
        } else {
            return $val;
        }
    }
}

详细的代码待我完成Yii系列最佳时间贡献到githun供大伙下载研究呢。

Response

看完了请求的引导,咱们来看下咱们如何反馈给用户吧。

Yii是经过response这个组件来反馈给用户咱们想要给到他的信息的。

Response对象包含的信息有HTTP状态码,HTTP头和主体内容等, 网页应用开发的最终目的本质上就是根据不一样的请求构建这些响应对象。

响应中首当其冲的应该就是状态码了,也就是咱们以前提到的404啊,503啊,301啊,这些都是服务器的状态码。

Yii提供了一些常量去定义这些状态码

yii\web\BadRequestHttpException:状态码 400。
yii\web\ConflictHttpException:状态码 409。
yii\web\ForbiddenHttpException:状态码 403。
yii\web\GoneHttpException:状态码 410。
yii\web\MethodNotAllowedHttpException:状态码 405。
yii\web\NotAcceptableHttpException:状态码 406。
yii\web\NotFoundHttpException:状态码 404。
yii\web\ServerErrorHttpException:状态码 500。
yii\web\TooManyRequestsHttpException:状态码 429。
yii\web\UnauthorizedHttpException:状态码 401。
yii\web\UnsupportedMediaTypeHttpException:状态码 415。

yii\web\Response::statusCode 状态码默认为200, 若是须要指定请求失败,可抛出对应的上诉的HTTP异常。

若是想抛出的异常不在如上列表中,可建立一个yii\web\HttpException异常, 带上状态码抛出,以下:

throw new \yii\web\HttpException(402);

可在 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::$content属性, 例如:

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

Yii可使用以下的几种格式

HTML: 经过 yii\web\HtmlResponseFormatter 来实现.
XML: 经过 yii\web\XmlResponseFormatter来实现.
JSON: 经过 yii\web\JsonResponseFormatter来实现.
JSONP: 经过 yii\web\JsonResponseFormatter来实现.
RAW: use this format if you want to send the response directly without applying any formatting.

通常的话,咱们不会这么麻烦的去操做,而是直接和前端商量好,咱们会以哪一种形式返回给你,而后直接在action里面直接返回数据给用户。

Web基类中对应的方法:

public function sendSuccess($message = null, $data = [], $code = "0")
    {
        return $this->formatJson([
                'response' => [
                    'header' => [
                        'code' => $code,
                        'msg' => $message
                    ],
                    'body' => $data ?: []
                ]
            ]
        );
    }

    public function sendError($message = null, $code = "1")
    {
        return $this->formatJson([
                'response' => [
                    'header' => [
                        'code' => (string)$code,
                        'msg' => $message ? $message : '未知错误'
                    ],
                ]
            ]
        );
    }

session

除了Request和Response这两个基本概念,还有个概念比较重要,若是你想让你用户的数据在你后端构成一个map,你可使用session这个组件,相信我,这个组件绝对可以知足大部分用户登陆系统,用他来保存用户的数据很是方便,每次用户来请求,只须要将sessionId传给你,你就能够获取到这个用户的状态,虽然方便,但不能彻底保证安全,若是sessionId被截取了,这也是至关蛋疼的事。这就要看系统的健壮性了,用户的敏感信息是否会在前端有权限拿到,若是要拿敏感信息,你的系统又当如何。

这里很少说,会在安全那一章和大伙好好唠唠后台应用中提升安全系数的一些作法呢。

下面直接上session相关的代码,session的操做也很简单,key-value模型。

$session = Yii::$app->session;

// 检查session是否开启 
if ($session->isActive) ...

// 开启session
$session->open();

// 关闭session
$session->close();

// 销毁session中全部已注册的数据
$session->destroy();

比较重要的一个方法是设置session存在的时间:

$session->setTimeout(...)

session数据的存储和提取

$session = Yii::$app->session;

// 获取session中的变量值,如下用法是相同的:
$language = $session->get('language');
$language = $session['language'];
$language = isset($_SESSION['language']) ? $_SESSION['language'] : null;

// 设置一个session变量,如下用法是相同的:
$session->set('language', 'en-US');
$session['language'] = 'en-US';
$_SESSION['language'] = 'en-US';

// 删除一个session变量,如下用法是相同的:
$session->remove('language');
unset($session['language']);
unset($_SESSION['language']);

// 检查session变量是否已存在,如下用法是相同的:
if ($session->has('language')) ...
if (isset($session['language'])) ...
if (isset($_SESSION['language'])) ...

// 遍历全部session变量,如下用法是相同的:
foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ...

Flash数据是一种特别的session数据,它一旦在某个请求中设置后, 只会在下次请求中有效,而后该数据就会自动被删除。喜欢的朋友能够去官方文当中详查。

关于cookie,后端使用的较少,前端用的时候常常用它来存储一些数据。这里很少说,感兴趣的朋友能够去官方文当中详查。

至此,全部的关于用户的请求Yii是如何处理的就讲完啦,包括从URL解析,Request和Response组件,Session组件这一整套内容,其实,官网将错误处理,日志系统归类到这章,我感受这两章对于开发者来说仍是比较重要的,因此,我下面会分两个小章来详细讲讲这两个系统。^_^

相关文章
相关标签/搜索