处理Go中的base64解码错误

huangapple go评论104阅读模式
英文:

Handling errors from base64 decode in Go

问题

考虑以下简单的Base64解码代码片段:

package main

import (
    "fmt"
    "encoding/base64"
)

func main() {
    const encoded string = "aGVsbG8=" // hello
    decoded, err := base64.StdEncoding.DecodeString(encoded)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(decoded))
}

这将按预期输出_hello_。
现在,如果我故意传入损坏的输入,例如:

const encoded string = "XXXXXaGVsbG8="

那么我会触发 panic,得到以下错误信息:

panic: illegal base64 data at input byte 11

goroutine 1 [running]:
main.main()
    /tmp/sandbox422941756/main.go:12 +0x140

查看源代码和此问题,似乎除了匹配字符串文字并向调用者返回更有意义的错误消息之外,没有更多的方法:

if err != nil {
    if strings.Contains(err.Error(), "illegal base64 data at input byte") {
        panic("\nbase64 input is corrupt, check service Key")
    }
}

除了字符串匹配之外,是否有更优雅的方法来实现这一点呢?

英文:

Consider this simple base64 decode snippet:

package main

import (
    "fmt"
    "encoding/base64"
)

func main() {
    const encoded string = "aGVsbG8=" // hello
    decoded, err := base64.StdEncoding.DecodeString(encoded)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(decoded))
}

This produces hello as expected.
Now, if i intentionally pass in corrupt input, e.g.

const encoded string = "XXXXXaGVsbG8="

then i hit the panic line which gives me:

panic: illegal base64 data at input byte 11

goroutine 1 [running]:
main.main()
    /tmp/sandbox422941756/main.go:12 +0x140

Looking at the source code and this issue, seems there is not much to go by here other than matching the string literal and returning a more meaningful error message to the caller:

if err != nil {
    if strings.Contains(err.Error(), "illegal base64 data at input byte") {
        panic("\nbase64 input is corrupt, check service Key")
    }
}

There has to be a more elegant way to do this other than string matching.
What is the go-esque way to achieve this?

答案1

得分: 6

看一下错误类型。例如,

package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	encoded := "XXXXXaGVsbG8=" // 错误的
	decoded, err := base64.StdEncoding.DecodeString(encoded)
	if err != nil {
		if _, ok := err.(base64.CorruptInputError); ok {
			panic("\nbase64 输入损坏,请检查服务密钥")
		}
		panic(err)
	}
	fmt.Println(string(decoded))
}

输出:

panic: 
base64 输入损坏,请检查服务密钥
英文:

Look at the error type. For example,

package main

import (
	"encoding/base64"
	"fmt"
)

func main() {
	encoded := "XXXXXaGVsbG8=" // corrupt
	decoded, err := base64.StdEncoding.DecodeString(encoded)
	if err != nil {
		if _, ok := err.(base64.CorruptInputError); ok {
			panic("\nbase64 input is corrupt, check service Key")
		}
		panic(err)
	}
	fmt.Println(string(decoded))
}

Output:

panic: 
base64 input is corrupt, check service Key

答案2

得分: 1

查看实现(未导出的base64.Encoding.decode()方法),如果该方法返回错误,那么它只能是具体类型base64.CorruptInputError。这种错误类型总是产生以下错误字符串:

func (e CorruptInputError) Error() string {
    return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10)
}

因此,除了一些极端情况(如内存不足错误、修改的执行代码等),如果base64.StdEncoding.DecodeString()返回错误,它的错误字符串将始终包含字符串"illegal base64 data at input byte "(在当前版本中)。

检查其错误字符串是不必要的,您可以将任何非nil的返回错误视为输入无效。而且错误字符串是实现细节,因此您不应该依赖它。错误字符串是为了人类而不是代码。这就是encoding/base64包的实现方式,除此之外,您不能进行更精细的错误处理(通常在Encoding.DecodeString()的情况下不需要区分不同的错误情况)。

当一个包为不同的错误情况提供不同的错误值时,有一些处理它们的技巧。有关详细信息,请查看这个问题:

Does go have standard Err variables?

如上所述,在encoding/base64包的情况下,会返回具体类型base64.CorruptInputError的值,您可以使用类型断言来检查它。请参阅peterSO的答案。

英文:

Looking at the implementation (unexported base64.Encoding.decode() method), if that method returns an error, it can only be of concrete type base64.CorruptInputError. This error type always produces the following error string:

func (e CorruptInputError) Error() string {
	return "illegal base64 data at input byte " + strconv.FormatInt(int64(e), 10)
}

So beside some extreme circumstances (like out of memory error, modified execution code etc.) if base64.StdEncoding.DecodeString() returns an error, its error string will always contain the string "illegal base64 data at input byte " (in the current version).

It's needless to check its error string, you can treat any non-nil returned error as the input being invalid. And the error string is an implementation detail, so you shouldn't rely on it anyway. The error string is for humans, not for code. This is how the encoding/base64 package is implemented, you can't do any finer error handling beside this (and usually there is no need to distinguish separate error cases in case of Encoding.DecodeString()).

When a package does give distinct error values for different error cases, there are techniques to handle them well. For details, check out this question:

Does go have standard Err variables?

As mentioned, in case of the encoding/base64 package a value of the concrete base64.CorruptInputError type is returned, you can use type assertion to check for that. See peterSO's answer for that.

huangapple
  • 本文由 发表于 2017年7月2日 18:53:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/44870022.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定