python代码
import socket
import struct
import threading# FastCGI 头格式(8 字节)
FCGI_HEADER_FORMAT = "!BBHHBx"
FCGI_VERSION = 1
FCGI_TYPE_BEGIN_REQUEST = 1
FCGI_TYPE_PARAMS = 4
FCGI_TYPE_STDIN = 5
FCGI_TYPE_STDOUT = 6
FCGI_TYPE_END_REQUEST = 3
FCGI_RESPONDER = 1def parse_fcgi_header(data):"""解析 FastCGI 头"""version, type_, request_id, content_length, padding_length = struct.unpack(FCGI_HEADER_FORMAT, data)return version, type_, request_id, content_length, padding_lengthdef read_fcgi_record(client_socket):"""读取并解析 FastCGI 记录"""header = client_socket.recv(8) # 读取 8 字节头部if not header:return None, None, None, None, Noneversion, type_, request_id, content_length, padding_length = parse_fcgi_header(header)content = client_socket.recv(content_length) if content_length > 0 else b""client_socket.recv(padding_length) # 读取并丢弃填充数据return type_, request_id, content, content_length, padding_lengthdef parse_fcgi_params(data):"""解析 FastCGI PARAMS(key-value 形式)"""params = {}i = 0while i < len(data):name_length = data[i]value_length = data[i + 1]i += 2# 处理长度值大于 127 的情况if name_length >= 128:name_length = ((name_length & 0x7F) << 24) | (data[i] << 16) | (data[i+1] << 8) | data[i+2]i += 3if value_length >= 128:value_length = ((value_length & 0x7F) << 24) | (data[i] << 16) | (data[i+1] << 8) | data[i+2]i += 3name = data[i : i + name_length].decode("utf-8", errors="ignore")value = data[i + name_length : i + name_length + value_length].decode("utf-8", errors="ignore")params[name] = valuei += name_length + value_lengthreturn paramsdef handle_request(client_socket):"""处理 FastCGI 请求"""try:# 读取 BEGIN_REQUEST 记录type_, request_id, content, _, _ = read_fcgi_record(client_socket)if type_ != FCGI_TYPE_BEGIN_REQUEST:client_socket.close()return# 读取所有 PARAMS(FastCGI 请求参数)params_data = b""while True:type_, _, content, content_length, _ = read_fcgi_record(client_socket)if type_ != FCGI_TYPE_PARAMS or content_length == 0:break # 读取完成params_data += content# **使用修正的解析函数**param_dict = parse_fcgi_params(params_data)print("Received FCGI Params:", param_dict)# 读取 STDIN(HTTP 请求体)stdin_data = b""while True:type_, _, content, content_length, _ = read_fcgi_record(client_socket)if type_ != FCGI_TYPE_STDIN or content_length == 0:breakstdin_data += content# 生成 HTTP 响应response_body = b"Hello, FastCGI over TCP! (Threaded)"response_headers = b"Content-Type: text/plain\r\nContent-Length: %d\r\n\r\n" % len(response_body)stdout_data = response_headers + response_body# 发送 FastCGI 响应stdout_header = struct.pack(FCGI_HEADER_FORMAT, FCGI_VERSION, FCGI_TYPE_STDOUT, request_id, len(stdout_data), 0)end_header = struct.pack(FCGI_HEADER_FORMAT, FCGI_VERSION, FCGI_TYPE_END_REQUEST, request_id, 0, 0)client_socket.sendall(stdout_header + stdout_data) # 发送正文client_socket.sendall(end_header) # 发送结束标志except Exception as e:print(f"Error handling request: {e}")finally:client_socket.close()def start_fcgi_server(host="0.0.0.0", port=9000):"""启动 FastCGI 多线程 TCP 服务器"""server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_socket.bind((host, port))server_socket.listen(5)print(f"FastCGI Server listening on {host}:{port}")while True:client_socket, _ = server_socket.accept()thread = threading.Thread(target=handle_request, args=(client_socket,))thread.start() # 启动新线程处理请求if __name__ == "__main__":start_fcgi_server()
nginx添加配置
location /hello {include fastcgi_params;fastcgi_pass 127.0.0.1:9000;# 传递 FastCGI 相关参数fastcgi_param REQUEST_METHOD $request_method;fastcgi_param SCRIPT_FILENAME /dummy;fastcgi_param QUERY_STRING $query_string;fastcgi_param CONTENT_TYPE $content_type;fastcgi_param CONTENT_LENGTH $content_length;fastcgi_param PATH_INFO $fastcgi_script_name;
}
访问结果