Go中ASN1编解码时asn1:"-"标签为何不生效?
问题:Go标准库
encoding/asn1中asn1:"-"标签为何无法像json:"-"那样忽略结构体字段? 以下代码尝试对bearer结构体执行ASN.1编组:
type bearer struct { CreatedAt time.Time `asn1:"generalized"` ExpiresAt time.Time `asn1:"generalized"` Nonce string Signature []byte `asn1:"-"` TTL time.Duration `asn1:"-"` Frequency int `asn1:"-"` } c := &bearer{ CreatedAt: time.Now() ExpiresAt: time.Now().Add(1*time.Minute()) Nonce: "123456789abcdefghijklmnop" Frequency: 1 } b, err := asn1.Marshal(*c) os.WriteFile("b64.txt", b, 0777)
执行后通过Bash命令base64 -d b64.txt > b64.txt.der检查发现,标记为asn1:"-"的字段仍被编入结果,无值字段还出现“Error: Object has zero length.”错误。
原因分析
Go标准库encoding/asn1与encoding/json的标签逻辑完全不同:
json:"-"的作用是直接忽略字段,但asn1:"-"的功能是禁用字段的默认ASN.1标签编号,让字段使用上下文自动分配的编号,并不会跳过字段的编组流程。encoding/asn1的编组规则仅会跳过未导出字段(首字母小写),而导出字段无论是否标记-"标签,只要有值(或零值未触发omitempty)都会被处理。
解决方案
要彻底忽略指定字段,有两种可靠方式:
方式一:改为未导出字段
将不需要编组的字段首字母改为小写,ASN.1编组会自动跳过这些未导出字段:
type bearer struct { CreatedAt time.Time `asn1:"generalized"` ExpiresAt time.Time `asn1:"generalized"` Nonce string signature []byte // 首字母小写,自动忽略 ttl time.Duration // 首字母小写,自动忽略 frequency int // 首字母小写,自动忽略 }
方式二:使用中间结构体
如果需要保留原结构体的导出字段,可以定义仅包含需编组字段的中间结构体,转换后再执行编组:
type bearer struct { CreatedAt time.Time `asn1:"generalized"` ExpiresAt time.Time `asn1:"generalized"` Nonce string Signature []byte TTL time.Duration Frequency int } // 定义仅包含需编组字段的中间结构体 type bearerASN1 struct { CreatedAt time.Time `asn1:"generalized"` ExpiresAt time.Time `asn1:"generalized"` Nonce string } // 转换并执行编组 c := &bearer{ CreatedAt: time.Now(), ExpiresAt: time.Now().Add(time.Minute), Nonce: "123456789abcdefghijklmnop", Frequency: 1, } asn1Data := bearerASN1{ CreatedAt: c.CreatedAt, ExpiresAt: c.ExpiresAt, Nonce: c.Nonce, } b, err := asn1.Marshal(asn1Data) if err != nil { // 此处添加错误处理逻辑 } os.WriteFile("b64.txt", b, 0777)
额外修正:原代码的语法错误
原代码存在两处语法问题需要调整:
time.Minute是Duration常量,不是函数,需将time.Minute()改为time.Minute- 结构体初始化的每个字段末尾需要添加逗号,例如
CreatedAt: time.Now(),
内容的提问来源于stack exchange,提问作者armaka
相关产品推荐
相关产品推荐

