环境和情况
站点是工作在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方面提供解答