美文网首页
运行机制

运行机制

作者: 小羊羊爱吃饭 | 来源:发表于2017-05-24 17:37 被阅读104次

    yii处理http请求时,执行的流程是这样的:

    1、服务器接收到来自客户端(比如浏览器)的请求,服务器(比如nginx)根据一些转发规则把请求转发给入口脚本web/index.php
    2、入口加班加载配置文件,实例化一个应用。
    3、应用通过request应用组件解析路由。
    4、应用创建controller实例处理请求。
    5、controller创建action实例并为这个action执行相关的filter操作。
    6、如果任何一个filter验证失败,就不执行这个动作,如果全部的filter通过验证,就会继续执行
    7、动作会加载数据模型,一般从数据库中读取
    8、加载完数据渲染一个view,并且把需要的数据一起填充到这个view中。
    9、渲染得到的结果会返回给response组件。
    10、response组件把渲染结果返回给浏览器。

    下面是yii官方文档中的示意图。

    启动引导

    在应用开始解析并处理接受请求之前,要预先准备环境。启动引导会在两个地方执行,入口脚本和应用主体。在入口脚本里,需要注册各个类库的类文件自动加载器,加载配置文件,实例化应用主体。

    实例化应用主体,会执行应用主体的构造函数,在构造函数中做这些事:
    1、调用 yii\base\Application::preInit()方法,配置高优先级的应用属性。
    2、注册errorHandler函数
    3、调用init方法,运行引导组件。init方法做的事:1、加载vendor/yiisoft/extensions.php扩展清单文件,创建运行各个扩展的引导组件,创建并运行各个组件和在应用的bootstrap属性中声明的各个模块组件。

    因为引导工作必须在处理每一次请求之前都进行一遍,因此尽量不要注册太多引导组件。

    路由引导

    在入口脚本中调用yii\web\Application::run() 方法时,首先要解析输入的请求,用request组件的 yii\web\Request::resolve() 方法实现,确定该用哪个controller处理请求,然后实例化对应的controller处理请求,如果请求实在不能被确定该由哪个controller处理,request组件会抛出yii\web\NotFoundHttpException 异常。

    缺省路由

    如果请求没有提供具体的路由,这个时候就会启用yii\web\Application::defaultRoute 属性所指定的缺省路由。该属性的默认值为 site/index,它指向 site 控制器的 actionIndex,可以在配置文件中设置该属性。

    catchAll路由

    如果你的web服务整在维护,不想让用户访问,这个时候可以设置catchAll属性,它可以把所有的请求都解析到同一个路由。

    创建action

    一旦请求路由被确定了,紧接着就要创建action对象,用来响应这个路由。

    路由可以用斜线分割成多个组成片段,栗子:site/index可以分解为site和index,它们指向某一个module、controller或action。

    从路由的第一个片段开始,按下面的流程一次创建module、controller或action,如果这些步骤有任何错误发生,就会抛出yii\web\NotFoundHttpException。

    先找到site对应的controller。

    在controller里面找到index的action,如果找的到,就创建一个action对象,如果找不到,controller会尝试创建一个action和它相对应

    请求

    一个应用的请求是用yii\web\Request 对象来表示的,该对象提供了请求参数、HTTP头、cookies等信息,可以通过request组件获得相应的请求对象。

    这个组件提供了一些方法可以获得相关信息:

    获取请求的参数和方法
    yii\web\Request::get()
    yii\web\Request::post()
    yii\web\Request::getBodyParam()
    Yii::$app->request->method,

    获取Url信息
    假设被请求的URL是 http://example.com/admin/index.php/product?id=100, 可以像下面描述的那样获取URL的各个部分:

    yii\web\Request::url:返回 /admin/index.php/product?id=100, 此URL不包括host info部分。
    yii\web\Request::absoluteUrl:返回 http://example.com/admin/index.php/product?id=100, 包含host info的整个URL。
    yii\web\Request::hostInfo:返回 http://example.com, 只有host info部分。
    yii\web\Request::pathInfo:返回 /product, 这个是入口脚本之后,问号之前(查询字符串)的部分。
    yii\web\Request::queryString:返回 id=100,问号之后的部分。
    yii\web\Request::baseUrl:返回 /admin, host info之后, 入口脚本之前的部分。
    yii\web\Request::scriptUrl:返回 /admin/index.php, 没有path info和查询字符串部分。
    yii\web\Request::serverName:返回 example.com, URL中的host name。
    yii\web\Request::serverPort:返回 80, 这是web服务中使用的端口。

    获取HTTP头信息
    Yii::$app->request->header: 返回yii\web\HeaderCollection 对象
    yii\web\Request::userAgent:返回 User-Agent 头。
    yii\web\Request::contentType:返回 Content-Type 头的值, Content-Type 是请求体中MIME类型数据。
    yii\web\Request::acceptableContentTypes:返回用户可接受的内容MIME类型。 返回的类型是按照他们的质量得分来排序的,得分最高的类型将被最先返回。
    yii\web\Request::acceptableLanguages:返回用户可接受的语言。 返回的语言是按照他们的偏好层次来排序的。第一个参数代表最优先的语言。

    获取客户端信息
    yii\web\Request::userHost 获取host name
    yii\web\Request::userIP 获取客户机的IP地址

    响应

    当应用完成处理一个请求后, 会生成一个yii\web\Response响应对象并发送给客户端,响应对象包含的信息有HTTP状态码,HTTP头和主体内容等, web应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。

    HTTP状态码设置方法

    Yii::$app->response->statusCode = 200;

    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::$app->response->content = 'hello world!';
    如果在发送给终端用户之前需要格式化,应设置 yii\web\Response::format 和 yii\web\Response::data 属性,yii\web\Response::format 属性指定yii\web\Response::data中数据格式化后的样式,栗子:
    <pre>
    $response = Yii::$app->response;
    $response->format = \yii\web\Response::FORMAT_JSON;
    $response->data = ['message' => 'hello world'];
    </pre>

    Yii支持以下可直接使用的格式

    yii\web\Response::FORMAT_HTML
    yii\web\Response::FORMAT_XML
    yii\web\Response::FORMAT_JSON
    yii\web\Response::FORMAT_JSONP

    如果不指定,在action中调用render方法渲染视图默认yii\web\Response::FORMAT_HTML,

    上面介绍的这些方法可以被显式地设置,但是大多数情况下通过操作方法的返回值隐式设置,如果想使用其他格式,只需要在返回数据之前设置$response->format即可。

    浏览器跳转

    浏览器跳转依赖于发送一个Location
    HTTP 头,Yii是这样支持的:可以调用yii\web\Response::redirect() 方法将用户浏览器跳转到一个URL地址,在action中,可以调用缩写版的redirect,栗子:

    return $this->redirect('http://example.com/new', 301);

    这行代码会返回一个响应对象发送给终端用户,除了这个,还可以在redirect()之后再直接调用send()方法来确保没有其他内容追加到响应中。栗子:

    \Yii::$app->response->redirect('http://example.com/new', 301)->send();

    yii\web\Response::redirect() 方法默认会设置响应状态码为302,该状态码会告诉浏览器请求的资源 临时 放在另一地址上,可传递一个301状态码告知浏览器请求的资源已经 永久 重定向到新的地址。

    如果当前请求是ajax请求,这样发送location是不会跳转的,解决办法:yii\web\Response::redirect() 方法设置一个值为要跳转的URL的X-Redirect 头,在浏览器用JavaScript 代码读取该头部值然后让浏览器跳转对应的URL。

    发送文件

    Yii提供这些方法支持各种文件的发送需求:

    yii\web\Response::sendFile(): 发送一个已存在的文件到客户端
    yii\web\Response::sendContentAsFile(): 发送一个文本字符串作为文件到客户端
    yii\web\Response::sendStreamAsFile(): 发送一个已存在的文件流作为文件到客户端

    发送响应####

    用yii\web\Response::send() 方法发送响应,在这个方法调用前响应的内容不会返回给客户端,默认在yii\base\Application::run() 结尾自动调用,也可以手动调用这个方法强制立刻发送。这个方法使用这些步骤发送响应:

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

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

    Sessions

    session可以通过session 应用组件访问sessions,它是
    yii\web\Session 的实例。session组件提供了这些属性和方法:
    <pre>
    $session = Yii::$app->session;
    if ($session->isActive) ...// 检查session是否开启
    $session->open(); // 开启session
    $session->close(); // 关闭session,多次调用open和close不会产生错误,因为方法内部会先检查session是否已经开启。
    $session->destroy(); // 销毁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) ...
    </pre>
    tips:使用session组件访问session数据的时候,如果session没有自动开启,和通过$_SESSION不同,使用$_SESSION之前需要先执行session_start().

    当session数据是数组时,session组件只允许修改第一层数据的值,但是可以读取第二层以后的数据,栗子:
    <pre>
    $session = Yii::$app->session;
    // 如下代码不会生效

    $session['captcha']['number'] = 5;
    $session['captcha']['lifetime'] = 3600;

    // 如下代码会生效:

    $session['captcha'] = [
    'number' => 5,
    'lifetime' => 3600,
    ];

    // 如下代码也会生效

    echo $session['captcha']['lifetime'];
    </pre>

    自定义Session存储

    yii\web\Session默认把session数据保存为文件,Yii提供下面这些类可以保存为不同的形式:

    yii\web\DbSession: 保存到数据库
    yii\web\CacheSession: 保存到缓存,需要在配置文件中配置相关的缓存组件
    yii\redis\Session: 保存到redis

    这些session类都支持相同的api,因此切换不同的session类不需要修改使用session的代码。

    tips:如果通过$_SESSION访问使用自定义存储介质的session,需要确保session已经用yii\web\Session::open() 开启, 因为只有在这个方法中会注册自定义session存储处理器。

    Cookies

    Yii使用 yii\web\Cookie对象来代表每个cookie,yii\web\Request(维护请求提交的cookies) 和 yii\web\Response(维护返回给用户的cookies) 通过名为'cookies'的属性维护一个cookie集合。

    读取cookies,栗子:
    <pre>
    $cookies = Yii::$app->request->cookies;

    // 获取名为 "language" cookie 的值,如果不存在,返回默认值"en"
    $language = $cookies->getValue('language', 'en’);

    // 另一种方式获取名为 "language" cookie 的值
    if (($cookie = $cookies->get('language')) !== null) {
    $language = $cookie->value;
    }

    // 可将 $cookies当作数组使用
    if (isset($cookies['language'])) {
    $language = $cookies['language']->value;
    }

    // 判断是否存在名为"language" 的 cookie
    if ($cookies->has('language')) ...
    if (isset($cookies['language'])) ...
    </pre>
    发送cookies,栗子:
    <pre>
    $cookies = Yii::$app->response->cookies;
    // 在要发送的响应中添加一个新的cookie
    $cookies->add(new \yii\web\Cookie([
    'name' => 'language',
    'value' => 'zh-CN',
    ]));

    // 删除一个cookie
    $cookies->remove('language');

    // 等同于以下删除代码
    unset($cookies['language']);
    </pre>

    相关文章

      网友评论

          本文标题:运行机制

          本文链接:https://www.haomeiwen.com/subject/dksoxxtx.html