Golang 报错:接口转换错误:接口 {} 是 nil,而不是字符串。

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

Golang panic: interface conversion: interface {} is nil, not string

问题

我已经尝试创建CA配置文件、证书和私钥,我正在使用Go语言中的cfssl命令,并尝试从以下命令模拟相同的命令:

cfssl gencert -initca ca-csr.json | cfssljson -bare ca

以下是我的代码片段:

package main

import (
    "bytes"
    "fmt"
    "io"
    "os/exec"

    "github.com/cloudflare/cfssl/log"

    "encoding/json"
    "io/ioutil"
    "os"

    "github.com/cloudflare/cfssl/cli"
    "github.com/cloudflare/cfssl/cli/bundle"
    "github.com/cloudflare/cfssl/cli/certinfo"
    "github.com/cloudflare/cfssl/cli/gencert"
    "github.com/cloudflare/cfssl/cli/gencrl"
    "github.com/cloudflare/cfssl/cli/genkey"
    "github.com/cloudflare/cfssl/cli/info"
    "github.com/cloudflare/cfssl/cli/ocspdump"
    "github.com/cloudflare/cfssl/cli/ocsprefresh"
    "github.com/cloudflare/cfssl/cli/ocspserve"
    "github.com/cloudflare/cfssl/cli/ocspsign"
    printdefaults "github.com/cloudflare/cfssl/cli/printdefault"
    "github.com/cloudflare/cfssl/cli/revoke"
    "github.com/cloudflare/cfssl/cli/scan"
    "github.com/cloudflare/cfssl/cli/selfsign"
    "github.com/cloudflare/cfssl/cli/serve"
    "github.com/cloudflare/cfssl/cli/sign"
    "github.com/cloudflare/cfssl/cli/version"

    //  err "github.com/hyperledger/fabric/cop/errors"

    "google.golang.org/grpc"
)

func main() {

    var participantFile string = "key.pem"
    // file, err := os.Open("conf/ca-csr.json")
    // if err != nil {
    //  log.Fatalf("missing config file: %v", err)
    // }
    // defer file.Close()
    // s, err := ioutil.ReadAll(file)
    // if err != nil {
    //  log.Fatalf("could not read config file: %v", err)
    // }

    csr := `{
        "CN": "admin",
        "key": {
          "algo": "rsa",
          "size": 2048
        },
        "names": [
          {
            "C": "US",
            "L": "Portland",
            "O": "system:masters",
            "OU": "Kubernetes The Hard Way",
            "ST": "Oregon"
          }
        ]
      }`

    //csr := string([]byte(s[:]))
    GenCert(csr, participantFile)
}

var cfsslCmds = map[string]*cli.Command{
    "bundle":         bundle.Command,
    "certinfo":       certinfo.Command,
    "sign":           sign.Command,
    "serve":          serve.Command,
    "version":        version.Command,
    "genkey":         genkey.Command,
    "gencert":        gencert.Command,
    "gencrl":         gencrl.Command,
    "ocspdump":       ocspdump.Command,
    "ocsprefresh":    ocsprefresh.Command,
    "ocspsign":       ocspsign.Command,
    "ocspserve":      ocspserve.Command,
    "selfsign":       selfsign.Command,
    "scan":           scan.Command,
    "info":           info.Command,
    "print-defaults": printdefaults.Command,
    "revoke":         revoke.Command,
}

// CertMgr is the default certificate manager
type CertMgr struct {
    rootPath            string
    participantFilePath string
    cert                []byte
    grpcServer          *grpc.Server
}

type output struct {
    Cert string
}

type gencertOutput struct {
    cert []byte
    csr  []byte
    key  []byte
}

func GenCert(csr string, participantFile string) {
    var args []string

    gencertCmd := cfsslCmds["gencert"]
    var c cli.Config
    c.IsCA = true

    args = append(args, csr)

    out := ExecuteCommand(args, gencertCmd, c)

    var gencertOut map[string]interface{}
    json.Unmarshal([]byte(out), &gencertOut)

    var writeJSON output
    writeJSON.Cert = gencertOut["cert"].(string)
    jsonOut, _ := json.Marshal(writeJSON)

    ioutil.WriteFile(participantFile, jsonOut, 0644)

    return

}

func ExecuteCommand(args []string, command *cli.Command, c cli.Config) string {

    cfsslJSONCmd := exec.Command("cfssljson", "-bare")

    old := os.Stdout
    r, w, _ := os.Pipe()
    os.Stdout = w

    err := command.Main(args, c) // Execute command
    if err != nil {
        log.Error(err)
    }

    outC := make(chan string)
    // copy the output in a separate goroutine so printing can't block indefinitely
    var buf bytes.Buffer
    go func() {
        io.Copy(&buf, r)
        cfsslJSONCmd.Stdin = &buf
        outC <- buf.String()
    }()

    w.Close()

    out := <-outC
    outByte := []byte(out)

    tmpFile, _ := ioutil.TempFile("", "tmp")
    defer os.Remove(tmpFile.Name())
    if _, err = tmpFile.Write(outByte); err != nil {
        fmt.Println("err: ", err)
    }

    os.Stdin = tmpFile
    os.Stdout = old // restoring the real stdout

    err = cfsslJSONCmd.Run() // Execute cfssljson -bare <prefix>
    if err != nil {
        log.Error(err)
    }

    return out // To be used to store in participant file
}

我得到了以下错误:

[ERROR] open {
"CN": "admin",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "Portland",
"O": "system:masters",
"OU": "Kubernetes The Hard Way",
"ST": "Oregon"
}
]
}: no such file or directory
2022/03/25 19:23:39 [ERROR] exit status 1
panic: interface conversion: interface {} is nil, not string
goroutine 1 [running]:
main.GenCert({0xb9179c, 0xda}, {0xb3a3f3, 0x7})
/home/Documents/git-repo/kunets-vpc-test/main.go:126 +0x229
main.main()
/home/Documents/git-repo/kunets-vpc-test/main.go:70 +0x31
任何帮助和建议将不胜感激,非常感谢!
<details>
<summary>英文:</summary>
I have tried to create CA configuration file, certificate and private key, I am using `cfssl` command in go and try to simulate same command from 
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
Here is my code snipped 
package main
import (
&quot;bytes&quot;
&quot;fmt&quot;
&quot;io&quot;
&quot;os/exec&quot;
&quot;github.com/cloudflare/cfssl/log&quot;
&quot;encoding/json&quot;
&quot;io/ioutil&quot;
&quot;os&quot;
&quot;github.com/cloudflare/cfssl/cli&quot;
&quot;github.com/cloudflare/cfssl/cli/bundle&quot;
&quot;github.com/cloudflare/cfssl/cli/certinfo&quot;
&quot;github.com/cloudflare/cfssl/cli/gencert&quot;
&quot;github.com/cloudflare/cfssl/cli/gencrl&quot;
&quot;github.com/cloudflare/cfssl/cli/genkey&quot;
&quot;github.com/cloudflare/cfssl/cli/info&quot;
&quot;github.com/cloudflare/cfssl/cli/ocspdump&quot;
&quot;github.com/cloudflare/cfssl/cli/ocsprefresh&quot;
&quot;github.com/cloudflare/cfssl/cli/ocspserve&quot;
&quot;github.com/cloudflare/cfssl/cli/ocspsign&quot;
printdefaults &quot;github.com/cloudflare/cfssl/cli/printdefault&quot;
&quot;github.com/cloudflare/cfssl/cli/revoke&quot;
&quot;github.com/cloudflare/cfssl/cli/scan&quot;
&quot;github.com/cloudflare/cfssl/cli/selfsign&quot;
&quot;github.com/cloudflare/cfssl/cli/serve&quot;
&quot;github.com/cloudflare/cfssl/cli/sign&quot;
&quot;github.com/cloudflare/cfssl/cli/version&quot;
//  err &quot;github.com/hyperledger/fabric/cop/errors&quot;
&quot;google.golang.org/grpc&quot;
)
func main() {
var participantFile string = &quot;key.pem&quot;
// file, err := os.Open(&quot;conf/ca-csr.json&quot;)
// if err != nil {
//  log.Fatalf(&quot;missing config file: %v&quot;, err)
// }
// defer file.Close()
// s, err := ioutil.ReadAll(file)
// if err != nil {
//  log.Fatalf(&quot;could not read config file: %v&quot;, err)
// }
csr := `{
&quot;CN&quot;: &quot;admin&quot;,
&quot;key&quot;: {
&quot;algo&quot;: &quot;rsa&quot;,
&quot;size&quot;: 2048
},
&quot;names&quot;: [
{
&quot;C&quot;: &quot;US&quot;,
&quot;L&quot;: &quot;Portland&quot;,
&quot;O&quot;: &quot;system:masters&quot;,
&quot;OU&quot;: &quot;Kubernetes The Hard Way&quot;,
&quot;ST&quot;: &quot;Oregon&quot;
}
]
}`
//csr := string([]byte(s[:]))
GenCert(csr, participantFile)
}
var cfsslCmds = map[string]*cli.Command{
&quot;bundle&quot;:         bundle.Command,
&quot;certinfo&quot;:       certinfo.Command,
&quot;sign&quot;:           sign.Command,
&quot;serve&quot;:          serve.Command,
&quot;version&quot;:        version.Command,
&quot;genkey&quot;:         genkey.Command,
&quot;gencert&quot;:        gencert.Command,
&quot;gencrl&quot;:         gencrl.Command,
&quot;ocspdump&quot;:       ocspdump.Command,
&quot;ocsprefresh&quot;:    ocsprefresh.Command,
&quot;ocspsign&quot;:       ocspsign.Command,
&quot;ocspserve&quot;:      ocspserve.Command,
&quot;selfsign&quot;:       selfsign.Command,
&quot;scan&quot;:           scan.Command,
&quot;info&quot;:           info.Command,
&quot;print-defaults&quot;: printdefaults.Command,
&quot;revoke&quot;:         revoke.Command,
}
// CertMgr is the default certificate manager
type CertMgr struct {
rootPath            string
participantFilePath string
cert                []byte
grpcServer          *grpc.Server
}
type output struct {
Cert string
}
type gencertOutput struct {
cert []byte
csr  []byte
key  []byte
}
func GenCert(csr string, participantFile string) {
var args []string
gencertCmd := cfsslCmds[&quot;gencert&quot;]
var c cli.Config
c.IsCA = true
args = append(args, csr)
out := ExecuteCommand(args, gencertCmd, c)
var gencertOut map[string]interface{}
json.Unmarshal([]byte(out), &amp;gencertOut)
var writeJSON output
writeJSON.Cert = gencertOut[&quot;cert&quot;].(string)
jsonOut, _ := json.Marshal(writeJSON)
ioutil.WriteFile(participantFile, jsonOut, 0644)
return
}
func ExecuteCommand(args []string, command *cli.Command, c cli.Config) string {
cfsslJSONCmd := exec.Command(&quot;cfssljson&quot;, &quot;-bare&quot;)
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
err := command.Main(args, c) // Execute command
if err != nil {
log.Error(err)
}
outC := make(chan string)
// copy the output in a separate goroutine so printing can&#39;t block indefinitely
var buf bytes.Buffer
go func() {
io.Copy(&amp;buf, r)
cfsslJSONCmd.Stdin = &amp;buf
outC &lt;- buf.String()
}()
w.Close()
out := &lt;-outC
outByte := []byte(out)
tmpFile, _ := ioutil.TempFile(&quot;&quot;, &quot;tmp&quot;)
defer os.Remove(tmpFile.Name())
if _, err = tmpFile.Write(outByte); err != nil {
fmt.Println(&quot;err: &quot;, err)
}
os.Stdin = tmpFile
os.Stdout = old // restoring the real stdout
err = cfsslJSONCmd.Run() // Execute cfssljson -bare &lt;prefix&gt;
if err != nil {
log.Error(err)
}
return out // To be used to store in participant file
}
and I am getting that error
[ERROR] open {
&quot;CN&quot;: &quot;admin&quot;,
&quot;key&quot;: {
&quot;algo&quot;: &quot;rsa&quot;,
&quot;size&quot;: 2048
},
&quot;names&quot;: [
{
&quot;C&quot;: &quot;US&quot;,
&quot;L&quot;: &quot;Portland&quot;,
&quot;O&quot;: &quot;system:masters&quot;,
&quot;OU&quot;: &quot;Kubernetes The Hard Way&quot;,
&quot;ST&quot;: &quot;Oregon&quot;
}
]
}: no such file or directory
2022/03/25 19:23:39 [ERROR] exit status 1
panic: interface conversion: interface {} is nil, not string
goroutine 1 [running]:
main.GenCert({0xb9179c, 0xda}, {0xb3a3f3, 0x7})
/home/Documents/git-repo/kunets-vpc-test/main.go:126 +0x229
main.main()
/home/Documents/git-repo/kunets-vpc-test/main.go:70 +0x31
Any help advice would be appreciated, thank you very much! 
</details>
# 答案1
**得分**: 4
我认为你在 goroutine 运行时关闭了 w,并且以某种方式突然结束了进程或读取命令输出。尝试通过打印 "out" 来确认,如果是这个问题,可以使用 defer 关闭 w。
使用安全转换来避免 panic,并使用 spew.Dump(需要外部库)来检查数据。
或者使用调试器。
```go
variable, ok := something.(string)
if !ok {
// 无法转换为字符串,现在该怎么办???
}
英文:

I think you are closing the w while the goroutine is running and somehow it ends abruptly the process or reading the command output. Try confirm by print the “out” and if it is the issue, close w with defer

Use a safe convertion to avoid panic and use spew.Dump (need external library) to inspect the data.

Or use a debugger

variable, ok := something.(string)
if !ok {
  // cant convert to string, now what???
}

</details>



# 答案2
**得分**: 0

我在模拟时遇到了类似的问题

```go
type MockSomethingRepository struct {
	mock.Mock
}

func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
	args := msr.Called(id)

	return args.Get(0).(*entity.Session), args.Error(1)
}

然后我尝试像这样使用模拟对象:

mockSomethignRepository.On("FindById", "1").Return(nil, fmt.Errorf("something went wrong"))

我得到了类似的错误interface conversion: interface {} is *[]entity.Session, not []entity.Session

我在https://go.dev/play/p/CLyY2y9-2VF找到了解决方案,所以我通过以下方式解决了问题:

type MockSomethingRepository struct {
	mock.Mock
}

func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
	args := msr.Called(id)

	if args.Error(1) != nil {
		return nil, args.Error(1)
	}

	return args.Get(0).(*entity.Session), args.Error(1)
}

我没有解释,但它有效!

英文:

I was struggling with a similar problem when I was mocking.

type MockSomethingRepository struct {
mock.Mock
}
func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
args := msr.Called(id)
return args.Get(0).(*entity.Session), args.Error(1)
}

and Then I tried to use the mock like this

mockSomethignRepository.On(&quot;FindById&quot;, &quot;1&quot;).Return(nil, fmt.Errorf(&quot;something went wrong&quot;))

I got similar error nterface conversion: interface {} is *[]entity.Session, not []entity.Session

I have found solution in https://go.dev/play/p/CLyY2y9-2VF
so I have solved it by

type MockSomethingRepository struct {
mock.Mock
}
func (msr *MockSomethingRepository) FindById(id string) (*entity.Session, error) {
args := msr.Called(id)
if args.Error(1) != nil {
return nil, args.Error(1)
}
return args.Get(0).(*entity.Session), args.Error(1)
}

I don't have an explanation but It works!

huangapple
  • 本文由 发表于 2022年3月26日 03:54:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/71622424.html
匿名

发表评论

匿名网友

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

确定