在使用workerman 创建 wss 客户端调用通义千问的实时语音合成模型时, 使用官方示例写法设置hearder后, 千问服务端却返回 401 。 但是使用官方的python 示例脚本没有问题。 还有如果使用原始拼接发送hearder 也没有问题。 是不是Bug呢 ?
1.有问题的: workerman手册示例写法:
$worker = new Worker();
$worker->onWorkerStart = function() use ($API_KEY) {
$ws = new AsyncTcpConnection("ws://dashscope.aliyuncs.com:443/api-ws/v1/realtime?model=qwen-tts-realtime");
$ws->transport = 'ssl';
$ws->headers = [
"Host: dashscope.aliyuncs.com",
"Authorization: Bearer $API_KEY",
"User-Agent: Workerman-WebSocket-Client",
"Upgrade: websocket",
"Connection: Upgrade",
"Sec-WebSocket-Key: " . base64_encode(random_bytes(16)),
"Sec-WebSocket-Version: 13"
];
// 握手成功
$ws->onConnect = function($connection) {
echo "握手成功,可以通信了...\n";
};
// 接收服务端返回消息
$ws->onMessage = function($connection, $data) {
echo "收到消息: $data\n";
};
$ws->onError = function($connection, $code, $msg) {
echo "出错 [$code] $msg\n";
};
$ws->onClose = function($connection) {
echo "连接已关闭\n";
};
$ws->connect();
}
输出信息:
握手成功,可以通信了...
Sec-WebSocket-Accept not found. Header:
HTTP/1.1 401 Unauthorized
x-request-id: 7a696c29-a890-443f-a49a-58e182721f93
content-type: application/json
content-length: 109
x-envoy-upstream-service-time: 4
date: Tue, 16 Sep 2025 09:09:01 GMT
server: istio-envoy
req-cost-time: 4
req-arrive-time: 1758013741363
resp-start-time: 1758013741367
vary: Accept-Encoding
connection: close
连接已关闭
2. 可以正常运行的: workerman 比较原始的拼接发送hearder:
$worker = new Worker();
$worker->onWorkerStart = function() {
$API_KEY = 'sk-xxxx';
$path = "/api-ws/v1/realtime?model=qwen-tts-realtime";
$secKey = base64_encode(random_bytes(16));
$raw = "GET $path HTTP/1.1\r\n";
$raw .= "Host: dashscope.aliyuncs.com\r\n";
$raw .= "Upgrade: websocket\r\n";
$raw .= "Connection: Upgrade\r\n";
$raw .= "Sec-WebSocket-Key: $secKey\r\n";
$raw .= "Sec-WebSocket-Version: 13\r\n";
$raw .= "User-Agent: Workerman-WebSocket-Client\r\n";
$raw .= "Authorization: Bearer " . $API_KEY . "\r\n";
$raw .= "\r\n";
// 建立一个 SSL/TCP 连接到 443(ssl://)
$conn = new AsyncTcpConnection('ssl://dashscope.aliyuncs.com:443');
$conn->onConnect = function($c) use ($raw) {
echo "已连接,发送原始握手请求...\n";
$c->send($raw);
};
$conn->onMessage = function($c, $rawData) {
echo "=== 服务器响应开始 ===\n";
echo $rawData . "\n";
echo "=== 服务器响应结束 ===\n";
// 打后直接关连接
$c->close();
};
$conn->onError = function($c, $code, $msg) {
echo "连接/发送错误: [$code] $msg\n";
};
$conn->connect();
};
输出信息:
已连接,发送原始握手请求...
=== 服务器响应开始 ===
HTTP/1.1 101 Switching Protocols
upgrade: websocket
connection: upgrade
sec-websocket-accept: 0eO4LqIZ6T9E0u+vqpcjmd6DGGU=
date: Wed, 17 Sep 2025 01:31:47 GMT
server: istio-envoy
=== 服务器响应结束 ===
=== 服务器响应开始 ===
~{"event_id":"event_DnN9IwmPCLLyQigDxLvoY","type":"session.created","session":{"object":"realtime.session","mode":"server_commit","model":"qwen-tts-realtime","voice":"Cherry","response_format":"pcm","sample_rate":24000,"id":"sess_I
uMmaLRz7ri1FtkC5j28K"}}
=== 服务器响应结束 ===
第二种写法就是没有问题的。 为什么第一种推荐写法会不行呢, 这是什么原因, 是bug吗?
windows 10 系统, php7.4 , workerman V4.1.17
除了
"Authorization: Bearer $API_KEY"
其它头没必要写,其它头都是自动的
都尝试过了,就是因为单独写Authorization 不行, 才补上其他的头信息的, 也是不行
使用 ratchet/pawl 库也是没有问题的
tcpdump 抓包看看 数据流 。 具体哪里不一样