You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP转发Webhook至VB.Net TCP监听器的问题咨询

问题:Webhook转发时的HTTP头传递与TCP监听器数据流读取问题

我需要在r1节点接收Webhook后,转发到不同端口的r2目标地址。目前在r1部署了PHP脚本,但脚本无法保留并传递原始HTTP头,只能生成新请求头。现有PHP脚本能触发r2端的VB.Net TCP监听器,但监听器的ReadDataFromClient函数触发后,读取到的流数据为空。

已验证将Webhook转发至webhook.site可正常接收完整载荷,说明转发逻辑基础可行;尝试用HTTP监听器未收到数据,因此倾向继续使用TCP监听器。后续尝试通过getallheaders()获取并传递所有原始HTTP头,但转发失败,webhook.site未收到任何数据。现在希望仅传递4个特定HTTP头,并解决VB.Net TCP监听器无法读取流数据的问题。

具体问题:

  1. 如何将r1接收的原始HTTP头(仅指定4个)传递至r2?
  2. 为何r2的TCP监听器无法正常读取流数据,该如何修正?

一、传递指定HTTP头到r2的PHP实现

不要直接依赖getallheaders()(部分环境如FastCGI下兼容性差),改用$_SERVER数组提取指定头,同时必须构建完整的HTTP请求格式(请求行+头+空行+请求体),因为TCP监听器接收的是原始字节流,而非解析后的HTTP请求。

示例代码:

<?php
// 读取原始请求体
$requestBody = file_get_contents('php://input');
// 定义需要传递的4个目标HTTP头
$targetHeaders = [
    'X-Webhook-Signature',
    'Content-Type',
    'X-Event-Type',
    'X-Timestamp'
];

// 构建转发用的请求头数组
$forwardHeaders = [];
foreach ($targetHeaders as $header) {
    // 转换为$_SERVER兼容的键名格式
    $serverKey = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
    if (isset($_SERVER[$serverKey])) {
        $forwardHeaders[$header] = $_SERVER[$serverKey];
    }
}

// 配置r2的连接信息
$r2Host = 'r2的IP地址';
$r2Port = 你的目标端口;

// 建立TCP连接
$socket = fsockopen($r2Host, $r2Port, $errno, $errstr, 30);
if (!$socket) {
    die("连接失败: $errno - $errstr");
}

// 构建完整HTTP请求
$requestMethod = $_SERVER['REQUEST_METHOD'];
$requestUri = $_SERVER['REQUEST_URI'];
// 请求行
$requestLine = "$requestMethod $requestUri HTTP/1.1\r\n";
// 拼接头信息
$headerLines = [];
foreach ($forwardHeaders as $name => $value) {
    $headerLines[] = "$name: $value\r\n";
}
// 必须添加Content-Length,告知TCP端请求体长度
$headerLines[] = "Content-Length: " . strlen($requestBody) . "\r\n";
// 头与体之间用空行分隔
$headerLines[] = "\r\n";

// 拼接完整请求数据并发送
$fullRequest = $requestLine . implode('', $headerLines) . $requestBody;
fwrite($socket, $fullRequest);

// 可选:读取r2响应
$response = fread($socket, 8192);
echo $response;

// 关闭连接
fclose($socket);
?>

二、VB.Net TCP监听器读取流数据的修正

TCP监听器读取空数据的核心原因通常是:PHP端HTTP请求格式不完整,或VB端读取流的逻辑错误(提前关闭流、未按长度读取)。以下是修正后的实现:

Imports System.Net
Imports System.Net.Sockets
Imports System.Text

Module TCPListenerModule
    Private listener As TcpListener

    Sub Main()
        ' 绑定r2的监听地址和端口
        Dim ipAddr As IPAddress = IPAddress.Parse("0.0.0.0")
        listener = New TcpListener(ipAddr, 你的监听端口)
        listener.Start()
        Console.WriteLine("TCP监听器已启动,等待连接...")

        ' 异步接受新连接
        listener.BeginAcceptTcpClient(AddressOf OnClientConnected, Nothing)
        Console.ReadLine()
        listener.Stop()
    End Sub

    Private Sub OnClientConnected(ByVal ar As IAsyncResult)
        Dim client As TcpClient = listener.EndAcceptTcpClient(ar)
        Console.WriteLine("新客户端连接")

        ' 继续监听下一个连接
        listener.BeginAcceptTcpClient(AddressOf OnClientConnected, Nothing)

        ' 读取客户端数据
        ReadDataFromClient(client)
    End Sub

    Private Sub ReadDataFromClient(ByVal client As TcpClient)
        Dim stream As NetworkStream = client.GetStream()
        Dim buffer(4096) As Byte
        Dim totalBytesRead As Integer = 0
        Dim requestData As New StringBuilder()

        Try
            ' 先读取HTTP头,直到遇到头结束的空行(\r\n\r\n)
            While True
                Dim bytesRead As Integer = stream.Read(buffer, 0, buffer.Length)
                If bytesRead = 0 Then Exit While

                totalBytesRead += bytesRead
                requestData.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead))

                ' 检查是否读取到完整的HTTP头
                If requestData.ToString().Contains(vbCrLf & vbCrLf) Then
                    Exit While
                End If
            End If

            ' 解析Content-Length,获取请求体长度
            Dim contentLength As Integer = 0
            Dim headerEndIndex As Integer = requestData.ToString().IndexOf(vbCrLf & vbCrLf)
            Dim headers As String = requestData.ToString().Substring(0, headerEndIndex)
            For Each headerLine As String In headers.Split(vbCrLf)
                If headerLine.StartsWith("Content-Length:", StringComparison.OrdinalIgnoreCase) Then
                    Integer.TryParse(headerLine.Split(":")(1).Trim(), contentLength)
                    Exit For
                End If
            Next

            ' 读取剩余的请求体数据
            If contentLength > 0 Then
                Dim remainingBytes As Integer = contentLength - (totalBytesRead - (headerEndIndex + 4))
                While remainingBytes > 0
                    Dim bytesRead As Integer = stream.Read(buffer, 0, Math.Min(buffer.Length, remainingBytes))
                    If bytesRead = 0 Then Exit While

                    requestData.Append(Encoding.UTF8.GetString(buffer, 0, bytesRead))
                    remainingBytes -= bytesRead
                End If
            End If

            ' 输出完整请求内容
            Console.WriteLine("接收到的完整请求:")
            Console.WriteLine(requestData.ToString())

        Catch ex As Exception
            Console.WriteLine("读取数据出错:" & ex.Message)
        Finally
            stream.Close()
            client.Close()
        End Try
    End Sub
End Module

关键修正点:

  1. 先读取HTTP头直到识别到\r\n\r\n,再根据Content-Length读取对应长度的请求体,避免提前中断读取
  2. 循环读取缓冲区,确保获取完整的请求数据
  3. 读取完成后再关闭流和客户端连接,避免数据丢失

内容的提问来源于stack exchange,提问作者Tym

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:22:22