docker下Laravel无法找到除index.php外的php文件

出问题的docker-compose.yml文件

nginx的default配置文件


Laravel 的环境其实只需要把所有的正常请求导入到index.php(server.php)中进行处理就可以了。docker和普通环境都是这样的。

然而今天的坑就在于对于Nginx的文件检测并不是很了解(应该是不了解),以为nginx的请求打到php,php中返回文件是否存在,然后进行解析。相信很多人都是这么以为的,今天遇到的另一个问题,我就知道我公司的号称4年多经验的程序也是这么认为的。

先讲点别的

思路先拉出去(都是Nginx的问题),今天后台发现页面上上传一个2M以上的图片,就会出现上传“413 Request Entity Too Large”,600多KB的还是可以顺利上传的。

几个后台开发的果真是不了解Nginx,硬说是php的问题。从图上就可以看出来,这是Nginx报的错误。最简单的方式就是百度一下,“413 Request Entity Too Large”,为啥会出现这个问题。然后查看服务器里面的nginx.conf 和 conf.d 文件夹里面的所有文件,发现并没有设置客户端最大可以操作的数据包大小。没设置Nginx自然会给你设置一下,默认1M。对比出现的问题,2M以上的不能上传,600KB正常(1M图片没有,就不测了,也是懒),问题应该就在这里了。找个地方填入如下代码:

给点力直接给他来个20M,解决后患。

在Nginx中的配置的位置有两种:

  1. nginx.conf:在http{}中间加入上面代码。这个是全局的,影响到你配置的所有引用这个文件的虚拟机
  2. conf.d 文件下的 conf 文件:在 server{} 中间加入上面的代码。这个是局部的,只影响到添加的相关虚拟机

上面可以知道了,nginx在某些请求时是不会直接落到php的,nginx这边先判断完了,再走php,Nginx都走不通,php就不可能收到请求。

回归正题

并不是所有的请求都直接落到php的。

这个代码可以进行分析一下。

在根目录中有一个请求。比如说,https://idea.jinfeijie.cn/abc.php

$uri = abc.php

这时Nginx会去root后面紧跟的目录中查找是否又/var/www/app/abc.php文件存在。不存在,就把abc.php当成目录去查找,看目录/var/www/app/abc.php/ 是否存在,如果还不存在,就要重定向到index.php文件中了,构成/var/www/app/index.php?abc.php ,如果index.php也不存在,就通过Nginx直接返回404。

 

上面时我的代码目录片段,有两个php文件。访问index.php,没有任何的问题,然而访问别的东西,比如:https://idea.jinfeijie.cn/abc.php 或者 https://idea.jinfeijie.cn/phpinfo.php 都会出现下面的情况。

 

这是Laravel的404的报错页面。

从目录上看,所访问的目录只存在index.php 和 phpinfo.php 两个php文件。访问 abc.php 出现404报错页面是正常的,然而在目录中真实存在的文件却同样报了 404 的问题(文件不存在?不存在的),文件明明有的。

反推一下,既然时出现了laravel的404保持页面,肯定是进入了laravel的入口文件了(至于显示出来的内容是什么,完全是入口进入后根据输入输出的反馈),而在nginx.conf 中设置了最终跳转是index.php,所以入口就应该是那个正常显示的index.php了。何时会进入到index呢?两种情况吧,1.正常访问   2.到不到任何文件,Nginx给他重定向到index.php?xxxx

再反推一下,啥?phpinfo.php 文件找不到?明明在啊?这里又可以回到上一部分的总结了。

nginx在某些请求时是不会直接落到php的,nginx这边先判断完了,再走php,Nginx都走不通,php就不可能收到请求。

只看半句就行了,nginx这边先判断完了,再走php 。看个先后顺序,Nginx先,它先处理。nginx先判断文件是否存在,并不是落到php那边,先去解析。如果先落到php中去解析,这个phpinfo.php是完全可以解析出来的。

再看一下nginx的docker-compose.yml文件中的Nginx服务部分。

虽然再root中定义了code代码的路径是/var/www/app,但是构建镜像的时候并没有把代码放到这个目录中,同时,在建立服务的时候也没有把代码目录挂载到业务机的代码目录上去。此时的代码目录一直处于空状态,而我一直认为nginx代理了php-fpm的socket文件,是会同时可以读取php服务上的代码目录的,结果代理的只是个协议而已。nginx每一次的请求都找不到文件,又被try_files 到 index.php$query_string,往后没有其他规则,就会走到 php的解析的规则下,index.php落到了php-fpm,就返回出内容。由于index.php被强制解析了,就出现了只解析index.php的情况。

解决这个问题就需要把nginx的root目录挂载上php的代码目录。

docker与普通模式

docker下和普通模式最大的区别是docker每一个功能模块都被单独拎出来了,需要每一个细节都去把控,做的好就是做成集群也跟配一台服务器一样并且可以快速部署。而普通的lnmp架构,全部在一台服务器上,目录也是共享的,不会存在配了目录文件不存在的问题(挂载的情况)。

正确代码

正确的代码修改是非常简单的,并不需要修改什么东西,删掉原来部署好的服务,在nginx的docker-compose.yml文件上加入一条新的目录挂载指令。

nginx部分的完整部署代码: