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
分享

相关文章

10月 2, 2026

iOS 侧载(Sideloading)工具

AltStore 和 Sideloadly 都是目前最流行的 iOS 侧载(Sideloading)工具。 简单来说,它们的作用就是让你绕过苹果的官方 App Store,直接把第三方的 IPA 安装包(也就是 iOS 的应用安装文件)安装到你的 iPhone 或 iPad 上。 通过这两个工具,你

9月 28, 2026

注册 Chat Participant

将当前服务接入 VS Code 的 AI 聊天窗口是完全可行的。VS Code 在近期的版本中正式推出了 Chat Extensions API(github.copilot.chat),允许第三方扩展将自定义的 LLM 服务或工具注册到 Copilot Chat 面板中。 结合当前 code_ge

9月 23, 2026

php intelephense 设置 if 空格

在 VS Code 中,如果你使用的是 PHP Intelephense 插件,控制 if 关键字后面是否加空格的设置是由其内置的格式化引擎(基于 PSR-12 标准)决定的。 你可以通过修改 VS Code 的 settings.json 来配置这个行为: 1. 开启 if 后面的空格(默认/推荐

下一篇

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

上一篇

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

最近更新

  • 比尔盖茨的智慧:想多赚钱,就每天循环做这3件事
  • iOS 侧载(Sideloading)工具
  • 程序员越想创业,越不要急着动手
  • 注册 Chat Participant
  • 中秋给在外游子的一封信

热门标签

API CodeGeex Coding Cursor DeepSeek Docker Gitkraken Harness Laravel Management

目录

©2026 mdo. 保留部分权利。