Apache Thrift中PHP CGI脚本报错CGI script exit status 0xff00求助
Python3 CGI运行Thrift PHP服务端遇到的问题
我正在阅读Krzysztof Rakowski所著的《Learning Apache Thrift》一书,在第3章中,作者介绍了如何通过Python CGI在服务端执行PHP脚本,但书中使用的是Python2.7,因此我做了适配修改以兼容Python3。
通过python3 runserver.py命令启动基于Python CGI的Thrift服务端来运行PHP脚本,再用另一个终端执行python3 client.py命令调用客户端。
服务端输出
Starting server on port 8080... 127.0.0.1 - - [30/Oct/2022 11:05:17] "POST /MyFirstServer.php HTTP/1.1" 200 - 127.0.0.1 - - [30/Oct/2022 11:05:18] CGI script exit status 0xff00 127.0.0.1 - - [30/Oct/2022 11:05:18] "POST /MyFirstServer.php HTTP/1.1" 200 - 127.0.0.1 - - [30/Oct/2022 11:05:19] CGI script exit status 0xff00
客户端输出
logged current time to logfile (not waiting for response) Traceback (most recent call last): File "client.py", line 32, in <module> product = client.multiply(number1,number2) File "gen-py/myfirst/MyFirstService.py", line 79, in multiply return self.recv_multiply() File "gen-py/myfirst/MyFirstService.py", line 92, in recv_multiply (fname, mtype, rseqid) = iprot.readMessageBegin() File "thrift-0.17.0/lib/py/build/lib.macosx-10.11-x86_64-2.7/thrift/protocol/TBinaryProtocol.py", line 134, in readMessageBegin sz = self.readI32() File "thrift-0.17.0/lib/py/build/lib.macosx-10.11-x86_64-2.7/thrift/protocol/TBinaryProtocol.py", line 217, in readI32 buff = self.trans.readAll(4) File "thrift-0.17.0/lib/py/build/lib.macosx-10.11-x86_64-2.7/thrift/transport/TTransport.py", line 68, in readAll raise EOFError() EOFError
相关代码
runserver.py代码
#!/usr/bin/env python import os from http.server import HTTPServer, CGIHTTPRequestHandler class Handler(CGIHTTPRequestHandler): cgi_directories = ['/'] print("Starting server on port 8080...") HTTPServer(('', 8080), Handler).serve_forever()
client.py代码
#!/usr/bin/env python import sys, glob sys.path.append('gen-py') sys.path.insert(0, glob.glob('thrift-0.17.0/lib/py/build/lib.*')[0]) from myfirst import MyFirstService from thrift import Thrift from thrift.transport import THttpClient from thrift.transport import TTransport from thrift.protocol import TBinaryProtocol from random import randint try: # 'localhost', 8080, '/MyFirstServer.php' socket = THttpClient.THttpClient("http://localhost:8080/MyFirstServer.php") transport = TTransport.TBufferedTransport(socket) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = MyFirstService.Client(protocol) transport.open() # calling log method client.log("logfile.log") print("logged current time to logfile (not waiting for response)") # calling multiply method with random parameters number1 = randint(1,100) number2 = randint(1,100) product = client.multiply(number1,number2) print('%dx%d=%d' % (number1, number2, product)) # calling get_log_size method print("current size of logfile is: %d Bytes" % client.get_log_size("logfile.log")) # calling get_log_size method second time, but this time with wrong parameter print("current size of logfile is: %d Bytes" % client.get_log_size("no_such_file.log")) transport.close() except Thrift.TException as e: print("Received following error:\n error code: %d\n error desc: %s' % (e.error_code, e.error_description)")
PHP服务端代码
#!/usr/bin/env php <?php error_reporting(E_ERROR); define('THRIFT_PHP_LIB', __DIR__.'/thrift-0.17.0/lib/php/lib'); define('GEN_PHP_DIR', __DIR__.'/gen-php'); require_once THRIFT_PHP_LIB.'/Thrift/ClassLoader/ThriftClassLoader.php'; use Thrift\ClassLoader\ThriftClassLoader; $loader = new ThriftClassLoader(); $loader->registerNamespace('Thrift', THRIFT_PHP_LIB); $loader->registerDefinition('myfirst', GEN_PHP_DIR); $loader->register(); use Thrift\Protocol\TBinaryProtocol; use Thrift\Transport\TPhpStream; use Thrift\Transport\TBufferedTransport; class MyFirstHandler implements \myfirst\MyFirstServiceIf { public function log($filename) { date_default_timezone_set('UTC'); $time = date('Y-m-d H:m:s'); file_put_contents(__DIR__."/" . $filename, $time."\n", FILE_APPEND); error_log("Written " . $time . " to " . $filename); } public function multiply($number1, $number2) { error_log("multiply " . $number1 . " by " . $number2); return $number1 * $number2; } public function get_log_size($filename) { $filesize = filesize(__DIR__."/" . $filename); if ($filesize === false) { $e = new \myfirst\MyError(); $e->error_code = 1; $e->error_description = "Can't get size information for file " . $filename; error_log($e->error_description); throw $e; } error_log("size of log file " . $filename . " is " . $filesize . "B"); return $filesize; } }; header('Content-Type', 'application/x-thrift'); echo "\r\n"; $handler = new MyFirstHandler(); $processor = new \myfirst\MyFirstServiceProcessor($handler); $transport = new TBufferedTransport(new TPhpStream(TPhpStream::MODE_R | TPhpStream::MODE_W)); $protocol = new TBinaryProtocol($transport, true, true); $transport->open(); $processor->process($protocol, $protocol); $transport->close();
问题定位分析
CGI script exit status 0xff00通常表示PHP脚本未被正确执行,结合客户端的EOFError(无法读取服务端响应),可从以下几个方向排查:
PHP脚本执行权限与解释器路径
- 给PHP脚本添加可执行权限:
chmod +x MyFirstServer.php - 检查脚本首行
#!/usr/bin/env php是否有效,用which php获取系统PHP路径,若路径不符,替换首行(比如#!/usr/local/bin/php) - 直接在终端运行
php MyFirstServer.php,查看是否有语法或依赖报错
- 给PHP脚本添加可执行权限:
HTTP头输出错误
- PHP脚本中
header('Content-Type', 'application/x-thrift');写法错误,正确格式应为header('Content-Type: application/x-thrift');(用冒号分隔键值),错误的头输出会导致Thrift客户端无法解析响应
- PHP脚本中
Thrift依赖路径验证
- 确认
THRIFT_PHP_LIB和GEN_PHP_DIR定义的路径真实存在,且Thrift PHP库与生成的代码文件完整 - 若直接运行PHP脚本时报类找不到的错误,需修正依赖路径配置
- 确认
Python CGI环境配置
- 确保系统已安装PHP且
php命令在系统PATH中,Python的CGIHTTPRequestHandler需要能找到PHP解释器来执行脚本
- 确保系统已安装PHP且
内容的提问来源于stack exchange,提问作者user1503285
相关产品推荐
相关产品推荐

