用nginx反向代理webman的sse服务加上ssl时无法连接

zhaohanfeng

问题描述

参考社区的示例使用自定义进程方式写的sse服务,正常不使用nginx或者不使用ssl时可正常连接,但是加上ssl就不行,服务器上尝试相同的ssl配置用node写的sse示例能正常输出

程序代码

namespace process;

use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Protocols\Http\ServerSentEvents;
use Workerman\Protocols\Http\Response;
use Webman\Channel\Client;
use Workerman\Timer;

class EventSource
{

    protected $connections = [];

    /**
     * 函数描述
     * onWorkerStart
     * @author     :lance
     * @description:{初始化工作进程,并连接至channel服务}
     */
    public function onWorkerStart()
    {
        // 连接到 Channel 服务(默认监听 2206 端口)
        try {

            Client::connect(channelIP, channelPort);

            // 订阅消息频道
            Client::on('sse_message', function ($data) {

                $token = $data['token'] ?? false;
                if ($token && $token !== '' && isset($this->connections[$token])) {
                    foreach ($this->connections[$token] as $connection) { // 需自行维护连接池
                        $connection->send(new ServerSentEvents([
                            'event' => 'message',
                            'data'  => json_encode($data),
                            'id'    => $data['mid']
                        ]));
                    }
                }
            });

        } catch (\Exception $e) {
            error_log("Failed to connect to Channel service: " . $e->getMessage());
            return;
        }
    }

    /**
     * 函数描述
     * onMessage
     * @param TcpConnection $connection
     * @param Request       $request
     * @author     :lance
     * @description:{服务连接时进行消息推送}
     */
    public function onMessage(TcpConnection $connection, Request $request)
    {
        // 如果Accept头是text/event-stream则说明是SSE请求
       // if ($request->header('accept') === 'text/event-stream') {

            // 首先发送一个 Content-Type: text/event-stream 头的响应
            $connection->send(new Response(200, [
                'Content-Type'                 => 'text/event-stream',
                'Access-Control-Allow-Origin'  => '*', // 允许的域名
                'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',   // 允许的请求方法
                'Access-Control-Allow-Headers' => 'Content-Type, Authorization', // 允许的请求头
            ], '\r\n'));

            // 假设请求中带有用户标识,比如 URL ?uid=123
            $token = $request->get('token') ?? $connection->id;
            $connection->token = $token;
            $connectionId = $connection->id;

            // 保存该连接到全局数组中
            $this->connections[$token][$connectionId] = $connection;

            //默认发送一个hello信息
            $connection->send(new ServerSentEvents(['event' => 'message', 'data' => 'hello', 'id' => 1]));

            // 定时向客户端推送数据
            $timer_id = Timer::add(2, function () use ($connection, &$timer_id) {
                // 连接关闭的时候要将定时器删除,避免定时器不断累积导致内存泄漏
                if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
                    Timer::del($timer_id);
                    return;
                }
                // 发送message事件,事件携带的数据为hello,消息id可以不传
                $connection->send(new ServerSentEvents(['event' => 'message', 'data' => json_encode(['t'=>'hello']), 'id' => 1]));
            });
            return;
        //}
        $connection->send('ok');
    }

    /**
     * 函数描述
     * onClose
     * @param TcpConnection $connection
     * @author     :lance
     * @description:{关闭连接时,删除连接}
     */
    public function onClose(TcpConnection $connection)
    {
        if (isset($connection->token)) {
            if (isset($this->connections[$connection->token])) {
                if(isset($this->connections[$connection->token][$connection->id])){

                    // 删除连接
                    unset($this->connections[$connection->token][$connection->id]);
                }
            }
        }
    }
}

Nginx配置如下

server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  pdfapi.xxxx.cn;
        root        /mnt/sse;

        ssl_certificate "/mnt/ssl/xxxx/fullchain.cer";
        ssl_certificate_key "/mnt/ssl/xxxx/xxxx.cn.key";
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;

       #  Load configuration files for the default server block.
       # include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }

        location / {
            proxy_pass http://192.168.0.18:8687/;
            #proxy_pass http://127.0.0.1:3001/;
            proxy_http_version 1.1;
            proxy_set_header Connection '';
            proxy_buffering off;
            proxy_cache off;
            proxy_read_timeout 86400;
        }
    }

截图报错信息里报错文件相关代码

无ssl时能正常输出
截图
加上ssl时报错
截图
同样配置下node写的测试环境可以正常访问
截图

操作系统及workerman/webman等框架组件具体版本

系统为centos6.7,php版本为7.2,

136 2 0
2个回答

kof21411
location / {
        proxy_pass http://192.168.0.18:8687;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
}
  • zhaohanfeng 8天前

    应该不是nginx配置的原因,网上的配置基本我都试过了,我昨晚又试了webman2.1的版本是可以的反向代理的,我的webman版本是1.47

zhaohanfeng

找到原因了,第一次发的文件头,多了换行符“\r\n”,给大家参考

// 首先发送一个 Content-Type: text/event-stream 头的响应
            $connection->send(new Response(200, [
                'Content-Type'                 => 'text/event-stream',
                'Access-Control-Allow-Origin'  => '*', // 允许的域名
                'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',   // 允许的请求方法
                'Access-Control-Allow-Headers' => 'Content-Type, Authorization', // 允许的请求头
            ], '\r\n'));
  • 暂无评论
×
🔝