Lumen 初体验

介绍

Lumen:“为速度而生的 Laravel 框架”。

Lumen 是 Laravel 的作者(Taylor Otwell)的又一力作。简单、快速、优雅的它的特点,适合用于构建微服务架构和 API 应用。
官网:http://lumen.laravel.com
介绍:https://phphub.org/topics/701
中文文档:http://lumen.laravel-china.org/docs

安装

使用 composer 安装:

bashcomposer create-project laravel/lumen --prefer-dist

配置

Lumen 默认使用 .env 作为配置文件。.env.example 是官方给出的例子,直接拷贝命名为 .env

bashcd lumen
cp .env.example .env

调试模式

修改 .env 文件:

bashAPP_DEBUG=true

如果发现还是没有效果,再修改 lumen/bootstrap/app.php 文件,将 Dotenv::load 的注释移除掉。

疑问

1.为什么提示:not be found

访问:http://127.0.0.1/lumen/public/

显示:

bashSorry, the page you are looking for could not be found.

NotFoundHttpException in Application.php line 1121:

in Application.php line 1121
at Application->handleDispatcherResponse(array('0')) in Application.php line 1091
at Application->dispatch(null) in Application.php line 1026
at Application->run() in index.php line 28

查看路由文件 lumen/app/Http/routes.php

php$app->get('/', function() use ($app) {
    return $app->welcome();
});

感觉没有问题啊,和在 Laravel 中差不多的方式,那是哪里出了问题了?好的,先不管,尝试自己新定义一条路由规则试试看:

php$app->get('/test', function() use ($app) {
    return $app->welcome();
});

再访问:http://127.0.0.1/lumen/public/test

结果和刚才一样。

2.为什么会跳转

再尝试访问一下:http://127.0.0.1/lumen/public/test/
结果跳转到:http://127.0.0.1/test

解惑

我先来解释一下第 2 个问题,因为这是一个很多 Laravel 新手也经常问的问题。

原因何在?请看 lumen/public/.htaccess 文件:

bashRewriteRule ^(.*)/$ /$1 [L,R=301]

这是一条 Apache 路由重写规则(mod_rewrite 开启的情况下才有效),当请求的 URI 带有 /,就会匹配出 $1, 永久重定向(HTTP 状态码是 301)到根目录下的 $1。上面的例子中,匹配到 test(就是$1),就跳转至 /test 了。

如何来规避上面这个问题?注释这条 RewriteRule 吗?不是的。一般来说,我们应该避免使用末尾带斜杠的 URI。为什么 URI 末尾不应该带有斜杠呢?从语义是来说, test/ 表示目录,test 表示资源。还有,如果在 lumen/public 目录下真的有一个 test 目录,那么访问 http://127.0.0.1/lumen/public/test/,就会进入到 test 目录下面来,这不是我们想要的结果。(其实如果真的存在 test 目录并且不存在文件 test,那么,URI 末尾有没有斜杠都会进入到 test 目录中来,这是 Apache 决定的。因为它如果找不到文件,就会自动在末尾加个斜杠,尝试寻找目录下的 index.html 文件等等,具体是在 httpd.conf 中配置 DirectoryIndex。好吧,扯得太远了,拽回来)
总之,我还是建议 URI 末尾不要带 /,如果你非不听,那就注释上面那句 RewriteRule 吧,这样就不会重定向了。

关于第 1 个问题,我们也来分析一下发生的原因,这样才能对症下药。
根据错误提示,定位到文件 lumen/vendor/laravel/lumen-framework/src/Application.php 中:

php    /**
     * Dispatch the incoming request.
     *
     * @param  SymfonyRequest|null  $request
     * @return Response
     */
    public function dispatch($request = null)
    {
        if ($request) {
            $this->instance('Illuminate\Http\Request', $request);
            $this->ranServiceBinders['registerRequestBindings'] = true;

            $method = $request->getMethod();
            $pathInfo = $request->getPathInfo();
        } else {
            $method = $this->getMethod();
            $pathInfo = $this->getPathInfo();
        }        

        try {
            if (isset($this->routes[$method.$pathInfo])) {
                return $this->handleFoundRoute([true, $this->routes[$method.$pathInfo]['action'], []]);
            }

            return $this->handleDispatcherResponse(
                $this->createDispatcher()->dispatch($method, $pathInfo)
            );
        } catch (Exception $e) {
            return $this->sendExceptionToHandler($e);
        }
    }

匹配不到 route 的原因就在以上代码中。假设访问:http://127.0.0.1/lumen/public,那么 :

phpvar_dump($method);  // string(3) "GET"
var_dump($pathInfo);  // string(14) "/lumen/public/"

根据 lumen/app/Http/routes.php 中的定义,生成 $this->routes

phpvar_dump(array_keys($this->routes));  // array(2) { [0]=> string(4) "GET/" [1]=> string(8) "GET/test" }

由上可知, isset($this->routes[$method.$pathInfo]) 的结果就是 false,所以提示 not be found 了。
既然已经知道了原因,那问题就好解决了。解决的前提是不要改动框架的源代码,不然日后升级框架会多么蛋疼,你都把框架代码都修改,万一出了问题你咋办?你自己拆手机,官方是不保修的哦!当然,如果你是框架开发组的,你提交代码能被大家接受并被官方合并到主干代码中了,那你就改吧。

方案1:修改 DocumentRoot

修改 Apache 的配置文件 httpd.conf,将 DocumentRoot 指向 lumen/public

bashDocumentRoot "/sites/lumen/public"

重启 Apache。

但是,如果我还有其他站点也在这个 Apache 下面,改 DocumentRoot 就会导致其他的站点不能访问了。怎么办?请看方案 2

方案2:配置 Apache 虚拟主机

修改 httpd.conf,将下面这行的注释移除:

bashInclude etc/extra/httpd-vhosts.conf

修改 httpd-vhosts.conf

bash<VirtualHost *:80>
    DocumentRoot "/sites"
    ServerName 127.0.0.1
</VirtualHost>
<VirtualHost *:80>
    DocumentRoot "/sites/lumen/public"
    ServerName lumen.app
</VirtualHost>

重启 Apache。

修改主机的 etc/hosts,添加一行:

bash127.0.0.1 lumen.app

其中 127.0.0.1 应该换成你 lumen 应用存放的机器的 ip。

OK,这样就可以通过访问 http://lumen.app 来访问该 lumen 站点,通过 http://127.0.0.1 来访问其他站点。

但是,你压根不能修改 Apache 的配置,怎么办?请看方案 3

方案3.修改路由规则中的路径

改不了配置,就改代码喽(再强调一下,不是修改框架的源代码)。

修改路由文件 lumen/app/Http/routes.php

php
define('ROUTE_BASE', 'lumen/public'); $app->get(ROUTE_BASE . '/index', function() use ($app) { return $app->welcome(); }); $app->get(ROUTE_BASE . '/test', function() use ($app) { return $app->welcome(); });

这样,如果以后有变化的话,你只需要修改 define('ROUTE_BASE', 'lumen/public/');就可以了(当然,把这个写到应用配置项中是最合适的,部署时修改配置就可以了)。

至于想以 'lumen/public/' 作为首页 URI 显然是不可以的,建议使用 'lumen/pulbic/index' 作为首页。如同上面代码定义的路由规则那样。

因为,无论你在路由规则的字符串末尾加了多少个斜杠, $this->routes 的键是不会带有斜杠的,最终还是不能匹配的。原因在框架源代码中 lumen/vendor/laravel/lumen-framework/src/Application.php

php    /**
     * Add a route to the collection.
     *
     * @param  string  $method
     * @param  string  $uri
     * @param  mixed  $action
     */
    protected function addRoute($method, $uri, $action)
    {
        $action = $this->parseAction($action);

        $uri = $uri === '/' ? $uri : '/'.trim($uri, '/');

        if (isset($action['as'])) {
            $this->namedRoutes[$action['as']] = $uri;
        }

        if (isset($this->groupAttributes)) {
            if (isset($this->groupAttributes['prefix'])) {
                $uri = rtrim('/'.trim($this->groupAttributes['prefix'], '/').$uri, '/');
            }

            $action = $this->mergeGroupAttributes($action);
        }

        $this->routes[$method.$uri] = ['method' => $method, 'uri' => $uri, 'action' => $action];
    }

对,就是它:$uri = $uri === '/' ? $uri : '/'.trim($uri, '/');
所有,URI 末尾还是不带斜杠的好。


4.4k 声望
213 粉丝
0 条评论
推荐阅读
使用 Sentry 对应用进行监控,少 bug 少加班
产品新功能上线几周后,客户提工单反馈问题。研发同学经排查确认是 bug,且会产生脏数据。最终,修复 bug + 上线花了大半天,而编写修复脚本 + 修复数据耗费了一周。

Mr_Jing4阅读 3.7k

One 一个简洁的博客、微博客系统
代码:[链接]文档:[链接]系统预览首页:微博列表:微博详细:文章列表:文章详细:归档:搜索,目前只能依据分类、标签搜索😀:管理后台:

Eyeswap45阅读 2.3k评论 1

怎样用 PHP 来实现枚举?
在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠。枚举是一个被命名的整型常数的集合,枚举在日常生活中很常见,...

唯一丶25阅读 6.3k评论 4

Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 1.8k评论 2

封面图
微信公众号开发:自动回复文本/图片/图文消息/关键词回复/上传素材/自定义菜单
对接流程1、申请微信公众号测试账号URL:[链接]2、登录,配置开发者服务器URL和Token开发者服务器配置代码:config.php {代码...} URL是config.php在你服务器的URLToken是上面代码自己设置的Token搞定之后,就能完...

TANKING2阅读 10k

Hyperf 3.0 发布,PHP 新时代
在过去的一年半时间里,Hyperf 2.2 共发布了 35 个小版本,使 Hyperf 达到了一个前所未有的高度,这里也获得了一些不错的数据反馈。

huangzhhui3阅读 1k

封面图
多个著名 Go 开源项目被放弃,做大开源不能用爱发电,更不能只靠自己!
大家好,我是煎鱼。相信关注我的许多同学都有接触 Go 语言的开发,甚至在企业中多有实践。那么你在日常开发中,势必会接触到 gorilla 组织下的各个 Go 开源项目。如下图:gorilla/mux:Star:17.9k。a powerful r...

煎鱼1阅读 2.3k

4.4k 声望
213 粉丝
宣传栏