记录一次关于PHP收不到post信息的问题

环境和情况

站点是工作在OpenResty+PHP+Linux的,环境全部在docker下运行

发送端为golang进行post,php作为接收数据的服务端,以实现对frp的流控和鉴权操作

在基于原生实现的站点A上一直无法正确收到数据,但是站点B(我的死党好友编写的基于laraval的程序)却能够正确收到

分析

首先php收不到post数据不是什么奇怪事,老生常谈了,application/json类型接收起来就是麻烦一点

不过也就是$_POST和php://input的差别

或者$GLOBALS['HTTP_RAW_POST_DATA']理论上也行

然后咱们这边起了一个基准的测试脚本


$rawData = file_get_contents('php://input');
$headers = getallheaders();
$logData = [
    'raw_post_data' => $rawData,
    'raw_post_data1' => $GLOBALS['HTTP_RAW_POST_DATA'],
    'get' => $_GET,
    'post' => $_POST,
    'enable_post_data_reading' => (ini_get('enable_post_data_reading') ? 'On' : 'Off'),
    'headers' => $headers
];

$logMessage = json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
PrintLog($logMessage);
$response = [
    'status' => 'success',
    'message' => '数据已记录到日志文件。'
];

header('Content-Type: application/json');
echo json_encode($response, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

基本上是能收到的信息全部记录下来了

然后这是记录的信息

{
    "raw_post_data": "",
    "raw_post_data1": null,
    "proxy_name": null,
    "get": {
        "op": "NewProxy",
        "version": "0.1.0"
    },
    "post": [],
    "enable_post_data_reading": "On",
    "headers": {
        "X-Real-Ip": "x.x.x.x",
        "X-Frp-Reqid": "f9041d410124280d",
        "X-Forwarded-Proto": "https",
        "X-Forwarded-Host": "frp.moeworld.tech",
        "X-Forwarded-For": "x.x.x.x",
        "X-Forwarded-By": ":443",
        "Referer": "https:\/\/frp.moeworld.tech\/api\/v1\/MoeWorldFRP?op=NewProxy&version=0.1.0",
        "Content-Type": "application\/json",
        "Accept-Encoding": "gzip",
        "User-Agent": "Go-http-client\/1.1",
        "Host": "frp.moeworld.tech",
        "Content-Length": ""
    }
}
可以看到,和post有关的几个全是空的

那么会是post本来就是空数据吗?

当然不能排除这个可能,所以我们要进行排查

我们知道,HTTP(S)是TCP/IP协议组(这俩玩意放在一个是个组!)中关于Socket的一种实现

想要排除掉第三方干扰的话,那么直接起一个底层的Socket Server去监听端口即可

然后咱们就收到了一份这样的数据(有些东西被我删掉了)

User-Agent: Go-http-client/1.1
Content-Length: 213
Content-Type: application/json
X-Frp-Reqid: 2f3802d83a0b8f36
Accept-Encoding: gzip

{"version":"0.1.0","op":"NewProxy",
"content":{"user":{"user":"12345","metas":null,"run_id":"eb9b123a4c3234b49"},
"proxy_name":"12345.kPeJo123ROLKVinqle","proxy_type":"tcp","remote_port":26288}} 

总之这post数据肯定不是空的

不过这里也发现了个很草的事情,手工发请求回去给frps的时候,对面起码等了几分钟了,合着frp没有响应超时,握手成功了就一直等着啊

为什么laraval能收到?

首先可以肯定是,$request->body()和$request->input()能拿到

得益于compose和laraval这套基于编译型语言的设计的框架,上下文依赖看着让人感觉头大

不过咱猜测这玩意肯定还是用原生那套玩意去包装的

于是乎去研究了研究里面的依赖模块

最后感觉大概在Illuminate\Http\Request和Illuminate\Support\helpers里

不过大致看了看也没发现什么有用的信息

顺便也去问了问咱的好友,毕竟是他写的程序,而且作为laravaler,肯定比我熟悉laraval多了

不过哪怕是框架,塞个点原生的东西也能跑

这边我老规矩塞了个file_get_contents('php://input');结果也收到post请求体了

他那边也给出回复说,laraval并不会干预php://input,但是whmcs可能会

总之,到这里线索又断了

会是php的问题吗?

由于问题着实检查不出来,所以我打算做一个违背祖宗的决定

用python

php是个全家桶,上下游哪个出点毛病都可能会炸

偏偏这玩意还不能算致命的错误问题,连个日志都莫得,这么玄学的毛病也不知道去哪检查问题

相比之下隔壁python就没那么难查了

用python这边我最熟悉的flask框架起个server,直接run起来

如你所见的,啥毛病都没了

也只是因此,现在干脆拿python写这玩意了

docker跑个python又不是不行

顺便这次咱还一起玩了玩dockerfile去直接构建镜像环境,只能说比conda好使多了

性能差的机器conda一跑就死机,反而编译镜像算力负担还小不少,也是离谱

后记

不得不说这种问题是最折磨人的,浪费了一个下午和一个晚上,最后还是没搞定

原本这么多时间应该都能搓完一大半了

顺便也感谢好友iVampireSP提供的帮助,为我适配新版的frp提供了很多的思路,以及在laraval方面提供解答

点赞

赞助商广告

如果您的网络和设备条件允许,这里可能会显示来自Google和其他赞助商的广告

  1. Asuna说道:
    Google Chrome Android 10
    石粒

发表回复

电子邮件地址不会被公开。必填项已用 * 标注