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

使用go-xmpp连接ejabberd并发时遇auth failure: Nonce mismatch问题求助

解决go-xmpp多并发下ejabberd认证失败(Nonce mismatch)问题

问题描述

使用github.com/mattn/go-xmpp/xmpp Golang包向ejabberd发送消息,单用户请求正常,但多用户同时发起请求时,偶尔出现auth failure: Nonce mismatch认证失败错误。

原代码示例:

package main

import (
    "log"
    "time"
    "github.com/mattn/go-xmpp/xmpp"
)

func main() {
    options := xmpp.Options{
        Host:        "your_ejabberd_host",
        User:        "your_username",
        Password:    "your_password",
        Debug:       true,
        NoTLS:       false,
        DialTimeout: time.Second * 10,
    }

    conn, err := options.NewClient()
    if err != nil {
        log.Fatal("Failed to create XMPP client:", err)
    }

    // Send a sample message
    err = conn.Send(xmpp.Chat{
        Remote: "recipient_jid@example.com",
        Type:   "chat",
        Text:   "Hello, this is a test message!",
    })
    if err != nil {
        log.Fatal("Failed to send message:", err)
    }
    conn.Close()
    return
}

问题原因

Nonce mismatch错误通常和SASL认证流程中的随机数(Nonce)复用或并发冲突有关:

  • mattn/go-xmpp部分版本中,SASL认证的上下文状态存在非线程安全问题,多个goroutine共享或复用客户端实例时会导致Nonce不匹配;
  • 短时间内频繁创建连接,ejabberd端的SASL认证会话未及时清理,也会引发该错误。

解决方案

1. 保证每个请求使用独立客户端实例

每个并发请求必须创建独立的XMPP客户端连接,绝对不能复用xmpp.Options或xmpp.Client实例。修改后的并发安全示例:

package main

import (
    "log"
    "sync"
    "time"
    "github.com/mattn/go-xmpp/xmpp"
)

func sendMessage(username, password, recipient, text string) error {
    // 每个请求独立初始化Options和Client
    options := xmpp.Options{
        Host:        "your_ejabberd_host",
        User:        username,
        Password:    password,
        Debug:       true,
        NoTLS:       false,
        DialTimeout: time.Second * 10,
    }

    conn, err := options.NewClient()
    if err != nil {
        return err
    }
    defer conn.Close() // 确保连接使用后关闭

    return conn.Send(xmpp.Chat{
        Remote: recipient,
        Type:   "chat",
        Text:   text,
    })
}

func main() {
    var wg sync.WaitGroup
    users := []struct {
        username string
        password string
    }{
        {"user1@example.com", "pass1"},
        {"user2@example.com", "pass2"},
        // 可添加更多测试用户
    }

    recipient := "recipient_jid@example.com"
    for _, u := range users {
        wg.Add(1)
        go func(u struct{ username, password string }) {
            defer wg.Done()
            err := sendMessage(u.username, u.password, recipient, "Hello from concurrent sender!")
            if err != nil {
                log.Printf("User %s failed to send message: %v", u.username, err)
            } else {
                log.Printf("User %s sent message successfully", u.username)
            }
        }(u)
    }

    wg.Wait()
}

2. 升级go-xmpp到最新版本

社区可能已修复SASL认证的线程安全问题,执行命令升级包:

go get -u github.com/mattn/go-xmpp/xmpp

3. 调整ejabberd的SASL配置

在ejabberd配置文件(ejabberd.yml)中开启SASL缓存,减少重复认证压力:

sasl_options:
    cache: true
    cache_timeout: 60

4. 添加认证失败重试机制

针对偶发的Nonce不匹配错误,添加重试逻辑:

import "strings"

func sendMessageWithRetry(username, password, recipient, text string, retryTimes int) error {
    var err error
    for i := 0; i < retryTimes; i++ {
        err = sendMessage(username, password, recipient, text)
        if err == nil || !strings.Contains(err.Error(), "Nonce mismatch") {
            break
        }
        time.Sleep(time.Millisecond * 500) // 重试前短暂等待
    }
    return err
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:13:18