Authentication 一般指身份验证,又称“验证”、“鉴权”,是指通过一定的手段,完成对用户身份的确认。 Authorization 一般是授权、委托的意思,向…授予职权或权力许可,批准等意思。
所以你可以看一下 Laravel 的文档
讲完这个在说一说对应的 Http Status Code:
那么肯定有同学问了,为什么 401 是 Unauthorized 而不是 Unautheticated 呢?这不是坑人吗?事实上,参考 RFC,好像确实是弄错了。
我贴一篇解释,秒懂:原文链接
]]>There’s a problem with 401 Unauthorized, the HTTP status code for authentication errors. And that’s just it: it’s for authentication, not authorization. Receiving a 401 response is the server telling you, “you aren’t authenticated–either not authenticated at all or authenticated incorrectly–but please reauthenticate and try again.” To help you out, it will always include a WWW-Authenticate header that describes how to authenticate.
This is a response generally returned by your web server, not your web application.
It’s also something very temporary; the server is asking you to try again.
So, for authorization I use the 403 Forbidden response. It’s permanent, it’s tied to my application logic, and it’s a more concrete response than a 401.
Receiving a 403 response is the server telling you, “I’m sorry. I know who you are–I believe who you say you are–but you just don’t have permission to access this resource. Maybe if you ask the system administrator nicely, you’ll get permission. But please don’t bother me again until your predicament changes.”
In summary, a 401 Unauthorized response should be used for missing or bad authentication, and a 403 Forbidden response should be used afterwards, when the user is authenticated but isn’t authorized to perform the requested operation on the given resource.
“但是为什么 Linux 服务器上报这个错啊???”
1 2 |
|
“太诡异了,这怎么查?”
同事中又有人被这个问题坑了,你可以搜到很多人遇到这样的问题,我先告诉大家如何解决,再解释原因。
namespace
或 class
的名字的大小写弄错了?解决方案就这么简单,肯定是遇到了大小写的问题。
主要原因是 Mac 上的文件系统 HFS+ 默认是大小写不敏感(case-insensitive)的,当然可以修改为大小写敏感(case-sensitive)。 但是 Linux 系统却默认是大小写敏感的(case-sensitive),所以在 Mac 上能找到的文件,在 Linux 上却找不到。
当然为了了解这个问题,你还需要了解 PSR-4
的 autoload 方式。
因为历史的原因,如果你格式化为大小写敏感,很多软件都会有问题,比如大名鼎鼎的 Adobe 家的产品就有问题,刚才同事反馈,idea 家的软件也经常会莫名其妙崩溃(最终他不得不重新格式化为不敏感)。
你以为直接把文件名修改就可以解决问题了吗?你太年轻了,文件名大小写变化,git 根本没有任何察觉,还是那个原因,因为文件系统 HFS+ 默认是大小写不敏感的(case-insensitive),(谢谢 @NauxLiu 分享)你可以有这样几个选择:
方案一:
- 删除旧文件,提交代码。
- 添加新文件,提交代码。
方案二:修改配置
1
|
|
方案三:
1 2 3 |
|
希望对你有帮助。
]]>首先说一下我写这篇文章的初衷,在我们打算使用 Laravel Queue 的时候,你的首选应该是去看文档,但是无奈 Laravel 的文档很多地方写得太简单,有时候想了解一个深入的问题,不得不去看源码,但是看源码确实费一些时间。
所以我打算写一篇文章,把我在使用 Laravel Queue 过程中的方方面面都写一下,方便新手学习、老司机温习。
因为 Redis Queue 是比较简单也很常用的一种队列,所以以下内容我都基于 Redis Queue。
虽然这个问题不是今天文章的重点,但是我还要说一下,一般来说使用队列是为了:
- 异步
- 重试
也许你还有其他的理由使用队列,但是这应该是最基本的两个原因。
了解了为什么使用队列,那么一般有这么几类任务使用队列:
- 耗时比较久的,比如上传一个文件后进行一些格式的转化等。
- 需要保证送达率的,比如发送短信,因为要调用别人的 api,总会有几率失败,那么为了保证送达,重试就必不可少了。
使用队列的时候一定要想明白一个问题,这个任务到底是不是可以异步,如果因为异步会导致问题,那么就要放弃使用队列。
sync
,这样队列就变成了同步执行,方便调试队列里面的任务。handle
方法是可以注入别的 class 的,就像在 Controller action 里面也可以注入一样。queue:listen
什么时候使用 queue:work
?答:Laravel 5.3 的文档已经不写 queue:listen
这个指令怎么用了,所以你可以看出来可能官方已经不怎么建议使用 queue:listen
了,但是在本地调试的时候要使用 queue:listen
,因为 queue:work
在启动后,代码修改,queue:work
不会再 Load 上下文,但是 queue:listen
仍然会重新 Load 新代码。
其余情况全部使用 queue:work
吧,因为效率更高。
以下是常用的指令,我讲解一下
1
|
|
--daemon
The queue:work Artisan command includes a —daemon option for forcing the queue worker to continue processing jobs without ever re-booting the framework. This results in a significant reduction of CPU usage when compared to the queue:listen command
总体来说,在 supervisor 中一般要加这个 option,可以节省 CPU 使用。
--quiet
不输出任何内容
--delay=3
一个任务失败后,延迟多长时间
后再重试,单位是秒。这个值的设定我个人建议不要太短,因为一个任务失败(比如网络原因),重试时间太短可能会出现连续失败的情况。
--sleep=3
去 Redis 中拿任务的时候,发现没有任务,休息多长时间
,单位是秒。这个值的设定要看你的任务是否紧急,如果是那种非常紧急的任务,不能等待太长时间。
--tries=3
定义失败任务最多重试次数
。这个值的设定根据任务的重要程度来确定,一般 3 次比较适合。
1
|
|
如果一个任务进入 default 队列,会发生:
1 2 3 4 5 |
|
redis 中会出现如下内容:
1 2 |
|
如果执行命令:
1
|
|
Redis 会发生什么事情?
第一步:查看是否需要重启,如果 laravel:illuminate:queue:restart
存在,就重启队列(代码更新后,一定要重启队列,否则队列不会读取最新代码)。
1 2 |
|
第二步:查看zset queues:default:delayed
,注意这里的事务
1 2 3 4 5 6 7 8 9 |
|
第三步:查看 zset queues:default:reserved
,注意这里的事务
1 2 3 4 5 6 7 8 9 |
|
第四步:从 queue:default
list 中取任务,如果有任务,要把任务先暂存到 queues:default:reserved
中(过期时间60秒,Redis Queue 里面写一个任务最多执行60秒)。
任务执行结束会把 queues:default:reserved
中的任务删除,如果任务报错(Throw exception),也会把queues:default:reserved
中的任务删除,然后把任务扔进 queues:default:delay
,delay 的秒数是 3 秒(因为我们上面参数配置的是 --delay=3
)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
数据结构:
List
,
操作:
LRANGE "queues:default" 0 -1
获取 List 里面的所有数据。
数据结构:
Zset
,时间是 zset 的 score,通过 score 来排序。
操作:
ZRANGE ”queues:default:reserved“ 0 -1
获取 zset 里面的所有数据。
ZRANGEBYSCORE queues:default:reserved -inf +inf
通过时间来排序获取所有数据。
Redis 里面一个任务默认最多执行60秒,如果一个任务60秒没有执行完毕,会继续放回到队列中,循环执行,那酸爽(依稀记得那个加班的夜晚……..)
]]>我们的微服务使用 lumen 搭建,所以这里的测试都是指的是 api 的测试,而且我们没有写任何的单元测试,直接写的是系统测试,我举一个例子你就明白了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
以上的例子是测试在登陆的情况下,获取 xxx 的列表的接口的返回数据情况。
一般在测试的时候,因为每个测试数据库都要隔离,一般的解决方案有两种:
1. 第一种是使用 transaction
,每次在一个测试开始的时候transaction begin
,在断言结束后transaction rollback
,这样一个数据库中实际没有写入任何数据,所以每次测试互不影响,trait
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
migrate
,每次在一个测试开始的时候migrate
,在断言结束后migrate:rollback
,这样数据库每次测试都建表,写数据,清空数据和表格,所以每次测试也互不影响。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
我们的测试使用的是 sqlite :memory:
,配置如下:
1 2 3 4 |
|
很遗憾,sqlite :memory:
不支持 transaction
,只能使用 migrate
的方式。
随着测试越来越多,问题来了,我们一个有一个核心项目的系统测试已经有 97 个了,导致的问题是每次本地测试全部跑一次需要 8 分钟左右(每个人电脑不同,有些许差别),GitLab 上 ci 需要跑两次(一次自定义分支提交会跑,一次合并到 master 后会跑),结果就是一个 commit 从提交到审核代码到最终合并上线,需要十几分钟,真是的是心好痛。
最大的问题是,很多人一起开发,这个时间是会浪费在每一个人的头上,所以我们一直想办法尝试解决,但是并没有很好的解决方案。
因为我们使用的是 migrate
的方式,我们猜想可能使用 transaction
的方式可能会更快一点,而且也确实看到别人使用 mysql transaction
的方式测试速度加快了很多,就试用了一下,但是结果并不理想,甚至更慢。
放弃。
某天我看到 ruby
里面有比较成熟的并行测试方案,比如 parallel_tests ,觉得这是一个很好的思路,在测试使用多进程的方式来跑,就可以节省大量的时间,想想 php 不可能没有类似的工具 :),于是我找到了一个 Paratest,你可以通过 https://code.tutsplus.com/tutorials/parallel-testing-for-phpunit-with-paratest–net-32105 对 Paratest
有一定了解。
但是经过试用后,发现出现在不同 php 版本下,Paratest
很不稳定的,偶尔还抽风,决定放弃试用。
期间还遇到了别的类似的工具,但在兼容性上都做的很差,略失望。
偶然我观察到,在使用 phpunit
来跑全部测试的时候,比较慢的测试都在后面,这很奇怪,如果我使用 phpunit --filter XxxTest
的时候,事实上并没有那么慢,这是为什么?
既然单个文件跑的时候很快,那我试试一个文件一个文件来跑。如下:
1
|
|
以上代码的意思是从 tests 文件夹中找出所有 php 文件,最后单个使用 filter
的方式来跑测试,比如有一个文件是 ExampleTest.php
,最终执行的是 ./vendor/bin/phpunit --configuration phpunit.xml --filter ExampleTest
结果跑下来太震惊了,时间从 8 分 08 秒减到了 47 秒(在我机器),节省超过了 90% 的时间,一个字:”吓死人“。
难道是内存的原因吗?如果是内存的原因我在跑 phpunit 的时候,把 memory 调整到 limited,看看效果,
1
|
|
事实上,内存确实调整到了无限,但是仍然没有解决问题。
那到底是为什么呢?为什么把测试拆到多个文件,一个一个文件来跑比全部一起跑会快这么多?
而且,每个文件保持测试在 10 个以下,效果更佳。
直到现在,我还不可以更好的解释原因,如果你有线索,我们可以聊聊。
因为我们的 GitLab ci
里面会跑 phpunit,下面我分享下 .gitlab-ci.yml
配置
1 2 3 |
|
phpunit.sh,此脚本是我们架构师 @Sin30 写的
1 2 3 4 5 6 7 8 |
|
里面的 set -eo pipfail
解释以下:
set -e
表示一旦脚本中命令返回值不是 0,脚本立即退出;
set -o pipefail
表示在pipe |
中,只要任何一个命令返回值不是 0(假设是 -1),整个 pipe 返回 -1,即使最后一个命令返回 0。
这样可以保证只要有一个 Test 出错,后面的就不用再跑了,节省时间。
能节省程序员时间的事情是最重要的事情,怎么强调都不过分。
]]>1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
很自然的,在 Model (表在 new_mysql 数据库)里面我们会覆盖 connection
1
|
|
这个时候测试出问题了,因为我的测试配置是: database.php
1 2 3 4 |
|
phpunit.xml
1
|
|
因为 Model 里面 connection 写死了,所以在测试的时候会尝试去连 new_mysql
正确的做法应该是在 Model 里面通过覆盖 getConnectionName 来处理 testing 的数据库问题。
1 2 3 4 |
|
公司之前的项目是一个大杂烩,多个业务放在一个项目中,多个网站也是放在一起,因为总是有一些共用的数据,结果导致很多工程师同事在一个项目上开发,之前大家开开心心和和睦睦,平安无事,但是随着业务越来越复杂,问题出现了:
- 共用的东西很多,牵一发动全身,经常出现修改一些东西需要在多个业务里面测试,因为没有写单元测试,就只能手动测试。
- 每个人写的代码参差不齐,某天你想重构一些代码,但你看看要改那么多地方,你就只能苦笑,结果就是破罐子破摔,就像有洁癖的人,只能捏子鼻子闭着眼睛生活。
所以今年7月份,我们启动了核心项目的重构,整体来说就是拆服务,写 API,用 API。 今天我不讲整个过程是这么做的,我只分享重构前做的一些考虑,如果你也在做一些大的重构,希望这些考虑可以给你帮助。
项目重构可不单单只重构代码,这正是一个非常好的机会来重新梳理业务,可能你感觉业务跑的很顺,但是:
- 会不会有哪些业务已经是可有可无的状态?
- 会不会有哪个流程本来可以更简单?
- 会不会有一些遗留问题早就应该解决了,但是一直因为忙忙忙的缘故被拖后?
在重构的之前,技术人要完整的理解现有系统的结构,更重要的是要理解业务,尤其是要和第一线的业务人员进行沟通,了解他们的工作模式,了解他们的现有流程的一些困惑或难点。
了解清楚后,开始做减法,已经不需要的功能或流程要在老系统上进行精简或删除,可能你会问“我已经要重构了,为什么还需要在老系统上精简?“,因为你重构的系统还不知道什么时候上线呢,而且重构的系统再开发的时候需要参考老系统。
这一点是我考虑不足的地方,因为项目拉的比较长,时间预估方面也考虑不周,导致项目延期比较久。其中很重要的一个问题是:如何才能一步一步上线?
- 重构后的系统哪些部分可以先做完上线?让老系统与新系统的兼容工作分步做,而不是想着一步就全部替换掉,这不现实。
- 数据存储结构是否需要修改?如果修改,是否可以先洗一部分数据?
分步上线是把风险也分步,把风险分散开对一个成熟的业务非常关键。而且每一步都会给大家很多的信心,很清楚看到我们在前进,否则战线拉太长,大家都会觉得比较疲劳。
总体来说,这两点是在重构项目的时候大家都可以尝试考虑的问题,希望对你有帮助。
]]>最近做了一个网站项目,使用了 Laravel 5.3,就在昨天我们使用了 Laravel 5.3 的队列,driver 使用的是 Redis,简单好用。
本地测试顺利,CI 跑完,开开心心的上线。
Bang…… 出错日志疯一样的出现,如下:
1 2 3 4 5 6 7 |
|
看一下 RedisQueue 代码就会发现,现在的实现已经大部分都使用 LuaScript 来进行操作,不使用原生方法来操作,使用 LuaScript 来操作好处很多,比如:
这个时候我傻眼了,如果你是我,这个时候会怎么做?脑海里无数个想法:
很明显我没有眼花,而且如果3可以的话,肯定是最方便快速的方案,所以马上搜索,发现今年7月份阿里刚好推出了支持 lua 脚本的 Redis,只不过需要申请。
https://yq.aliyun.com/articles/57805
好开心,马上提交工单,一会就审核通过就开通了 lua 脚本的功能,完美解决。
温馨提示: 1. 开通支持 lua 脚本会有闪断。 2. 可能会丢数据,请做好 Redis 的备份工作,不过我们没有遇见这个问题。 3. 能开通就开通吧,说不准什么时候就用上了。:rose: :rose: :rose:
]]>这几个权限使用 Policy 可以很容易做出来,比如下面官网的例子,定义了 update 的 alibity:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Controller 中使用如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
我没进行思考,就直接想加到 policy 里面。
1 2 3 4 5 6 7 8 9 10 11 |
|
发现不行啊,细细的查看了 Gate 的实现,给你看一个函数你就懂了:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
在 authorize 的时候,Gate 会通过第一个参数(除去 user)来判断是哪个对象,知道了这个对象,才能找到对应的 policy class,所以一般我们这么用:
1 2 |
|
如果你想用 viewList,可以这么做:
1 2 3 4 5 6 7 8 9 10 11 |
|
是不是觉得很变扭,$class 这个参数我们根本就没有用,回过头想一想,这么做好像哪里不太对。。。。。。。。。。。
1 2 3 |
|
使用
1 2 3 4 |
|
查看 Gate 的代码,你会发现,他会优先 check policy 是否存在,不存在就会去检查是否有定义的 abilities,如果有就会使用,贴一段代码你就懂了:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1 2 3 4 5 6 |
|
Lumen 中的 routeResolver 有点不太一样,不能这样:
1
|
|
也不能这样:
1
|
|
报错:Call to a member function parameter() on array
所以正确的做法是自己解析:$request->route()
,略坑。
有人写了一个 helper 的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
就这么用吧。
可能你会问我为什么要自己去 request 中拿 route 的 parameter,因为我在 policy 中要用。
]]>项目创建后,第一次在敲 Namespace 的时候,不小心敲错了,本来应该是 App
,结果变成 app
,
每次创建的时候我都需要手动修改一下,PhpStorm 记住了第一次添加的 Namespace
那今天我创建了一个 Event 和 Listen (忘记修改 app
–> App
)后,添加好了对应的 ServiceProvider 后,发现 Listen 怎么都无法触发,Debug 所有的 Listeners 也没有发现。
后来细致检查代码才发现,真是自己坑了自己。
解决这个问题就是:删除 rm -rf .idea
这样之前写错的 Namespace 就没有了。
你们有遇见类似这样抓狂的问题吗?我感觉每次都是我自己挖坑,然后埋自己。
]]>场景是这样的,我使用 Guzzle 要调用一些 api,api 出错了我需要处理 Exception,这个时候我肯定会看一下 Guzzle 的文档,不过看文档稍微有点繁琐,如果你使用 PhpStorm,有更简单的办法:
第一步:选中 Guzzle 的 Exception 文件夹
第二步:选中 Show Diagram
结果:
是不是很神奇? 这个时候,我大概 Catch RequestException 来处理一下比较合理。
感谢郭师傅。
]]>现在有这么一个需求:如何实现匿名聊天?同时要实现实名聊天。
需求可以简单理解为:相同的用户 A 和 B,需要有三个会话,一个是实名的聊天,一个是 A 匿名 B 实名的聊天,一个是 A 实名 B 匿名的聊天。
咋一看好像没什么难度,直接使用云信提供的 SDK 来做就可以吧,但是这里的一个问题是:
云信提供的移动端 SDK(Android 和 iOS)有自己的一套会话系统,这个会话系统里面,每两个人都只能有一个会话,怎么办?
开始的时候,和移动端工程师商量:
后来选择了方案2,虽然移动端花了比较多的时间,但是最终实现了自己的会话,并且完成了匿名聊天。
给大家一个思路,供大家参考。
]]>$ git commit —amend
使用 Gerrit 过程中有这样的需求,如果想修改倒数第二个提交该怎么办?
可以使用 rebase -i 来操作:
git rebase -i HEAD~2
修改倒数第二个提交为:edit,保存退出
rebase 会停在倒数第二个提交,此时你可以修改代码。
修改完,执行 git commit —amend
(此时此刻,最后一个提交时倒数第二个提交)
git rebase —continue
珍惜自己的时间,珍惜别人的时间。
]]>就这么多吧。
]]>服务器端通过 Api 来发送消息的时候,只要消息超过一个大小,curl 就超时,HTTP 的 Response 没有任何的返回
在本地的几个服务器上使用没有上面的问题。
服务器上使用 tcpdump 发现在发送大的消息的时候,总会出现丢包重试的情况。
折腾了一段时间,确定是阿里云服务器的原因,就联系了阿里云的工程师进行联调,最后发现减小 MTU 的值可以解决上述问题。
一般 MTU 的默认值是 1500,当我们修改为 1360 的时候,就可以正常发送消息了。
分析待续。
]]>环信的优点是便宜,整体来说他的免费额度已经够你使用。但是当时时候的时候也遇见了几个比较严重的问题,比如丢消息的问题,解决了比较久仍然存在;比如 Server 端 API 很多功能不支持,竟然不能通过 API 来设置群聊的消息配置(接收且提醒,接收不提醒,不接受),以至于我们为了修改默认的群聊消息配置,不得不在客户端做一些恶心的操作;比如透传功能会影响消息功能,当时做了一个功能使用透传比较频繁,但是群聊的消息竟然被影响了,最后不得不去掉了透传。
最近开始使用网易云信,网易云信的第一个特点就是: 贵 。
免费额度只可以注册100人,注册满了100人就不能再新注册用户了,所以使用网易云信的免费额度机会不能做什么,调试一会就会消耗完免费额度。
下面我开始吐槽一下网易云信吧:
最后说一下网易云信的优点吧:
所以,如果你的公司有一定的经济能力,可以尝试使用网易云信,等网易云信聊天上线后,我再发一篇文章分析一下云信的情况,看会不会有坑。
]]>看着熟睡的花,我轻轻的侧身过去,拥着她,手放在她的皮肤上,像火一样暖,像水一样柔。
她轻轻的鼾声打在我的脸上,均匀细腻,可以闻到她懒懒的味道。
天蒙蒙亮,但仍然可以看清楚花平静的脸庞。
我的注视竟然吵醒了她。
她微微的一笑,我的心就化了。
]]>Logo 中规中矩,不丑,但不能很好和“新生大学”联系起来。
主要包括四个模块:文章,聊天,发现,我
整个 App 比较简单直接,已经完全可以满足写文章、阅读文章、交流等主要的几个功能,所以和我期待的 App 差距不大,比较担忧的是,想把朋友圈和聊天做得像微信那么流畅,确实不是一件容易的事情。
我的思考:
当然,App 现在还是有比较多的Bug,我边用边测,边测边提交 Bug,差不多提交了10个左右的 Bug,其中有几个还是比较严重,期待情非得已的团队可以尽快修复,辛苦你们啦。
希望可以在这个“大学”里面,做一名认真的新生,行动起来吧,少年。
在南方的北方人都会有这样的感受:冬天太难熬了,阴冷的空气常常会刺透你的肌肉,直达骨髓。所以我就幻想能有一种可以充电的秋裤,这个秋裤有如下的特征:
如果真的有了这样的秋衣秋裤,白天上班的时候我可以给秋衣秋裤充电,晚上回来穿上这样的秋衣秋裤,家里甚至不再需要开空调,不再需要其他的加热设备,因为我的衣服是热的,我完全可以抵挡冷空气进入我的骨髓,这样我深夜看书就不怕身体的某些地方被冻僵硬了。
在市面上搜索了一下,还没有类似的产品,只有绑着电热片的裤子,不太适合我的需求,我觉得这样的产品很快就会出现,哈哈。
每次去理发店我都会想念这样的一个机器。
每个男人的发型差不多都是固定的,所以我非常希望能有一种自动理发机,这种理发机可以做这么几件事情:
可以自动保存你的发型,包括你头发的每个区域的长度。 可以根据保存的发型进行自动剪发。
如果有这样的机器,不仅仅可以低成本理发,更重要的是发型设计就很简单了。
暂时还没发现有人在做这样的机器。
]]>