avatar

mdo

Hello

  • 首页
  • 知识库
  • 归档
  • 标签
  • 关于
主页 http协议推送websocket
文章

http协议推送websocket

发表于 2026-06-16 更新于 2026-06- 16
作者 mdo
8~11 分钟 阅读

在 think-swoole 中,如果需要通过 HTTP 接口(控制器)向指定的 WebSocket 客户端推送消息,你不能直接在控制器里使用 $websocket 变量,因为 HTTP 和 WebSocket 是两个独立的请求上下文。

要实现跨协议推送,必须使用 think-swoole 提供的 Swoole 场景服务(Context)。以下是具体的实现方案:

1. 控制器中实现 HTTP 推送

在你的控制器(Controller)方法中,注入 think\swoole\Websocket 类,并使用 to() 方法指定要接收消息的 fd(客户端标识),最后通过 push() 或 emit() 发送。

方案 A:原生 WebSocket 驱动

如果你使用的是标准原生 WebSocket,请使用 push() 方法:

php

<?php
namespace app\controller;

use think\Request;
use think\swoole\Websocket;

class PushController
{
    public function sendToUser(Request $request, Websocket $websocket)
    {
        // 从 HTTP 请求中获取接收者的 fd 和要发送的内容
        $fd   = $request->param('fd');
        $msg  = $request->param('message', '系统测试消息');

        if (!$fd) {
            return json(['code' => 400, 'msg' => '缺少参数 fd']);
        }

        // 指定 fd 并直接推送消息
        $websocket->to(intval($fd))->push($msg);

        return json(['code' => 200, 'msg' => "成功推送到客户端 FD: {$fd}"]);
    }
}

请谨慎使用此类代码。

方案 B:Socket.io 驱动

如果你在 config/swoole.php 中配置的是 socketio 驱动,请使用 emit() 方法:

php

// 指定 fd,触发前端监听的自定义事件(例如 'notice')
$websocket->to(intval($fd))->emit('notice', [
    'title'   => '系统通知',
    'content' => $msg
]);

请谨慎使用此类代码。


2. 常见业务场景:如何通过“用户 ID”推送?

在实际开发中,HTTP 接口通常只知道 user_id(用户ID),而不知道 Swoole 随机分配的 fd。因此,你需要在 WebSocket 连接成功(open 或 connect 事件)时,将两者绑定起来并存入 Redis。

步骤一:连接时绑定并存入 Redis

php

// app/listener/WsOpen.php (以原生 Websocket 为例)
namespace app\listener;

use think\swoole\Websocket;
use think\facade\Cache;

class WsOpen
{
    public function handle($event, Websocket $websocket)
    {
        $fd = $websocket->getSender();
        
        // 假设从连接 URL 参数中拿到了当前登录的 userId
        $userId = request()->param('user_id'); 
        
        if ($userId) {
            // 将 userId 和 fd 的对应关系存入 Redis(有效期根据业务定)
            Cache::store('redis')->set("uid_to_fd:{$userId}", $fd, 7200);
        }
    }
}

请谨慎使用此类代码。

步骤二:HTTP 接口通过用户 ID 查找并推送

php

// app/controller/PushController.php
public function sendToUid(Request $request, Websocket $websocket)
{
    $userId = $request->param('user_id');
    $msg    = $request->param('message');

    // 从 Redis 中取出该用户对应的 fd
    $fd = \think\facade\Cache::store('redis')->get("uid_to_fd:{$userId}");

    if (!$fd) {
        return json(['code' => 404, 'msg' => '用户不在线']);
    }

    // 推送
    $websocket->to(intval($fd))->push($msg);

    return json(['code' => 200, 'msg' => '推送成功']);
}

请谨慎使用此类代码。


3. 全局广播(推送给所有人)

如果你希望通过 HTTP 接口向所有当前连接的客户端群发消息,可以结合 broadcast() 方法使用:

php

// 广播给所有人 (原生 WebSocket)
$websocket->broadcast()->push("这是系统全局广播消息");

// 广播给所有人 (Socket.io 驱动)
$websocket->broadcast()->emit('allNotice', ['msg' => '全服通知']);

请谨慎使用此类代码。


接下来,你可以尝试创建一个 HTTP 路由来测试这个推送功能。

技术
许可协议:  CC BY 4.0
分享

相关文章

7月 26, 2026

完美地解决 TP3 老系统数据的平滑读取

为了彻底、完美地解决 TP3 老系统数据的平滑读取,必须解决两个核心痛点: TP3 的盲猜反序列化机制(标量存原样,数组/对象存原生 serialize,同时兼容 json)。 TP3 与 TP6 的缓存前缀(Prefix)不一致。 以下是为你量身定制的终极落地解决方案,通

7月 26, 2026

thinkphp3 redis序列化和反序列化

在老系统重构迁移至 ThinkPHP 6 (TP6) 的过程中,ThinkPHP 3 (TP3) 的 Redis 序列化历史遗留问题是最核心的连环坑之一。 TP3 的 S('key', $value) 缓存方法和底层 Redis 驱动,在存储非字符串(如数组、对象)时,有一套独特的序列化行为。如果不

7月 24, 2026

Table 空间极易发生哈希冲突并溢出

既然你没有在业务中主动调用 Room,只使用了全局广播,那么这个问题就非常明确了:即使你不用房间功能,think-swoole 只要开启了 WebSocket,底层就会强行初始化并注入一个名为 Room 的驱动组件。 [1] 框架底层默认使用 table 类型来作为 Room 的存储介质。当进行全局

下一篇

Swoole http server 如何处理http消息推送

上一篇

为命令创建专属“一键快捷键”

最近更新

  • 完美地解决 TP3 老系统数据的平滑读取
  • thinkphp3 redis序列化和反序列化
  • Table 空间极易发生哈希冲突并溢出
  • 将监控程序直接跑在云端
  • AI 驱动型 Facebook 群组关键词监控 Chrome 浏览器插件

热门标签

API CodeGeex Gitkraken Management Manticore Premiere Sublime Swoole ThinkPHP ThinkPHP5

目录

©2026 mdo. 保留部分权利。