“invalid character ‘\x1f‘ looking for beginning of value“ 报错解决方法

目录

问题背景

分析方法

问题原因


问题背景

这个问题来源于我在开启kubectl proxy代理的时候,通过kubectl apply -f xxx.yaml向代理提交一个configMap对象,返回了 "Error while proxying request: invalid character '\x1f' looking for beginning of value" 的报错。

分析方法

我通过打印请求,得到了 kubectl apply -f xxx.yaml 的基本流程:

  • 首先,会发起一个 GET /openapi/v2 的请求
  • 然后会发起一个 POST 请求,并且 body 中内容就是 yaml 文件的内容。

通过查询这个问题出现的原因得知,出现的原因是解析接口返回的字节符切片错误,出现了一堆乱码。解析失败是因为请求在 Header 里加入了Accept-Encoding: gzip,导致返回的结果被 gzip 压缩,然后返回的结果无法通过正常的 ioUtil.ReadAll(rsp.Body) 取出的内容去反序列化。

具体的解决手法参考见 invalid character '\x1f' looking for beginning of value

问题原因

沿着这个思路,我在开启的代理代码里面发现了一段返回结果的拦截

func (mtp *MyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
	rsp, err := mtp.RoundTripper.RoundTrip(req)
	if err != nil {
		return nil, err
	}

	defer rsp.Body.Close()

	b, err := ioutil.ReadAll(rsp.Body) //读取后,rsp body内容将就空了。需要重新赋值回去
	if err != nil {
		return nil, err
	}
	//序列化对象
	obj := unstructured.Unstructured{}
	if err = obj.UnmarshalJSON(b); err == nil {
		addCustomColumn(&obj, req)
		b, err = obj.MarshalJSON()
		if err != nil {
			return nil, err
		}
	} else {
		return nil, err
	}
	rsp.Body = ioutil.NopCloser(bytes.NewReader(b)) //tips 给body赋值的方法
	fmt.Println("响应对象类型:" + obj.GetKind())
	rsp.Header.Set("Content-Length", strconv.Itoa(len(b))) //这个很重要,如果修改了body内容需要重新计算长度
	return rsp, nil
}

原因是因为我需要在 kubectl get xxx 的时候对返回的结果反序列后修订内容,再序列化后返回。

参考网上的解决方法,方法一是删除 Header 中的 Accept-Encoding: gzip,方法二是添加一段读取 gzip 压缩内容 Body 的代码

if req.Header.Get("Accept-Encoding") == "gzip" {
	gr, err = gzip.NewReader(rsp.Body)
	if err != nil {
		return nil, err
	}
}

两种方法都没能成功,同样返回 "invalid character '\x03' looking for beginning of value"。

最后想到了,我其实并不需要为 /openapi/v2 这类的请求加工处理返回结果,所以只要跳过反序列化就可以,因此在 RoundTrip 中加入

//针对openapi做处理
if regexp.MustCompile(OpenApiPattern).MatchString(req.RequestURI) {
	return rsp, nil
}

最后 kubectl apply -f xxx.yaml 测试 ,通过。

你可能感兴趣的:(Kubernetes二次开发,golang学习之路,http,网络协议,网络)