golang MissingContentLength error

问题

金山云对象存储(KS3)的"PUT Object" API老是抛"MissingContentLength"!

原因

  • go http.NewRequest()接收os.File等非bytes.Buffer, strings.Buffer类型时无法设置ContentLength

注意: req.Header.set("Content-Length", xxx)是无效的! 最终以http.Request.ContentLength为准!

解决

  • 在http.NewRequest()时传递http.NoBody构建req对象后再自行设置ContentLength与GetBody
	req, err := http.NewRequest(http.MethodPut, getUrl("test2.go"), file)
	if err != nil {
		panic(err)
	}
	sta, _ := file.Stat()

	req.ContentLength = sta.Size()

完整源码


func main() {
	upload()
}

func upload() {

	file, err := os.Open(`C:\Users\Jason\Desktop\structmap.go`)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	file.Seek(0, io.SeekStart)
	req, err := http.NewRequest(http.MethodPut, getUrl("test2.go"), file)
	if err != nil {
		panic(err)
	}
	sta, _ := file.Stat()

	req.ContentLength = sta.Size()
	//req.Header.Set("Content-Length", strconv.FormatInt(sta.Size(), 10)) // 见上,设置Content-Length毛用...
	date := utcNow()
	req.Header.Set("Date", date)
	req.Header.Set("x-kss-acl", "private")
	req.Header.Set("Authorization", "KSS "+AK+":"+signature(http.MethodPut, "", "", date, "/hezhaowu/test2.go", "x-kss-acl:private"))

	bs, _ := httputil.DumpRequest(req, false)

	fmt.Printf("%s\n", bs)

	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer rsp.Body.Close()

	fmt.Println(rsp.Proto, rsp.Status)
	io.Copy(os.Stdout, rsp.Body)
}

func download() {
	req, err := http.NewRequest(http.MethodGet, getUrl("struct.go"), nil)
	if err != nil {
		panic(err)
	}

	date := utcNow()

	req.Header.Set("Date", date)
	req.Header.Set("Authorization", "KSS "+AK+":"+signature(http.MethodGet, "", "", date, "/hezhaowu/struct.go"))

	rsp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer rsp.Body.Close()

	fmt.Println(rsp.Proto, rsp.Status)
	io.Copy(os.Stdout, rsp.Body)
}

func signature(method string, contentMd5 string, contentType string, date string, name string, xobs ...string) string {
	var sb bytes.Buffer
	sb.WriteString(method)
	sb.WriteByte('\n')
	sb.WriteString(contentMd5)
	sb.WriteByte('\n')
	sb.WriteString(contentType)
	sb.WriteByte('\n')
	sb.WriteString(date)
	sb.WriteByte('\n')
	for _, v := range xobs {
		sb.WriteString(v)
		sb.WriteByte('\n')
	}
	sb.WriteString(name)

	h := hmac.New(sha1.New, []byte(SK))
	h.Write(sb.Bytes())
	return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

func getUrl(name string) string {
	return "https://" + DM + "/" + name
}

func utcNow() string {
	const layout = "Mon, 2 Jan 2006 15:04:05 GMT"
	return time.Now().UTC().Format(layout)
}

posted @ 2021-03-25 23:17  zolo®  阅读(78)  评论(0编辑  收藏  举报