使用gortsplib/v4实现RTSP摘要认证的问题求助
解决gortsplib/v4中RTSP摘要认证的问题
问题1:获取401响应头及错误详情
调用client.Describe()返回的错误若为*base.Error类型,内部包含完整响应对象,可通过类型断言提取响应头:
desc, resp, err := client.Describe(u) if err != nil { // 断言为base.Error类型以获取完整响应 if baseErr, ok := err.(*base.Error); ok { // 打印摘要认证所需的WWW-Authenticate头 fmt.Println("WWW-Authenticate:", baseErr.Response.Header.Get("WWW-Authenticate")) // 打印全部响应头 fmt.Println("响应头:", baseErr.Response.Header) } else { fmt.Println("普通错误:", err) } return }
注意你的代码存在流程错误:Describe后直接调用client.Close()会导致后续SetupAll、Play操作失效,必须移除提前关闭client的代码。
问题2:添加摘要认证信息到请求
gortsplib/v4已内置摘要认证自动处理逻辑,无需手动通过net包生成MD5摘要,以下两种方式任选:
方式1:提前设置认证凭据
启动client前直接配置用户名和密码,库会自动处理401重试及摘要生成:
client := &gortsplib.Client{} // 设置认证凭据 client.SetCredentials("你的用户名", "你的密码")
设置后,当首次请求返回401时,client会自动生成认证头并重试请求,无需手动发起两次DESCRIBE。
方式2:手动处理认证流程(自定义场景)
若需手动控制认证步骤,按以下流程操作:
- 发送首次DESCRIBE请求,获取401响应的
WWW-Authenticate头 - 解析头信息得到nonce、realm等参数
- 生成摘要认证的Authorization头
- 在后续请求中携带该头
示例代码片段:
// 首次发送DESCRIBE请求,获取401响应 desc, resp, err := client.Describe(u) if err != nil { baseErr, ok := err.(*base.Error) if !ok || baseErr.Response.StatusCode != base.StatusUnauthorized { panic(err) } // 解析WWW-Authenticate头参数 authHeader := baseErr.Response.Header.Get("WWW-Authenticate") authParams, err := base.ParseAuthenticateHeader(authHeader) if err != nil { panic(err) } // 生成Authorization头 authValue := base.GenerateAuthorizationHeader( "DESCRIBE", u, authParams, "你的用户名", "你的密码", ) // 构造带认证头的请求选项 reqOpts := &base.RequestOptions{ Header: base.Header{ "Authorization": {authValue}, }, } // 二次发送DESCRIBE请求 desc, resp, err = client.Describe(u, reqOpts) if err != nil { panic(err) } }
修正后的完整代码示例
package main import ( "fmt" "log" "github.com/bluenviron/gortsplib/v4" "github.com/bluenviron/gortsplib/v4/pkg/base" "github.com/bluenviron/gortsplib/v4/pkg/description" "github.com/bluenviron/gortsplib/v4/pkg/format" "github.com/bluenviron/gortsplib/v4/pkg/rtp" "github.com/pion/rtcp" ) func main() { // 解析RTSP地址 u, err := base.ParseURL("rtsp://<ip>:<port>/<path>") if err != nil { panic(err) } // 初始化客户端并设置认证信息 client := &gortsplib.Client{} client.SetCredentials("你的用户名", "你的密码") // 连接RTSP服务器 err = client.Start(u.Scheme, u.Host) if err != nil { panic(err) } defer client.Close() // 获取媒体描述 desc, _, err := client.Describe(u) if err != nil { panic(err) } // 建立所有媒体流连接 err = client.SetupAll(desc.BaseURL, desc.Medias) if err != nil { panic(err) } // 监听RTP数据包 client.OnPacketRTPAny(func(medi *description.Media, forma format.Format, pkt *rtp.Packet) { log.Printf("收到RTP包,媒体索引:%d", medi.Index) }) // 监听RTCP数据包 client.OnPacketRTCPAny(func(medi *description.Media, pkt rtcp.Packet) { log.Printf("收到RTCP包,媒体索引:%d,类型:%T", medi.Index, pkt) }) // 开始播放流 _, err = client.Play(nil) if err != nil { panic(err) } // 阻塞等待客户端运行(直到出现致命错误) panic(client.Wait()) }
内容的提问来源于stack exchange,提问作者Walter
相关产品推荐
相关产品推荐

