Golang调用Twitter API更新profile_banner报COMPRESSION_ERROR
问题根因
你遇到的GOAWAY + COMPRESSION_ERROR报错核心由两个错误用法导致:
- 参数传递位置错误:你将base64编码后的图片内容拼接在URL查询参数中传递。URL属于HTTP请求头域范畴,Twitter服务端、HTTP/2协议实现、链路中间代理对请求头长度都有严格的阈值限制(通常仅支持数KB),而个人主页横幅图片经base64编码后体积普遍在几十到上百KB,远超长度上限。服务端接收到被截断的、格式损坏的HTTP/2头压缩块时,校验失败就会主动断开连接,返回对应压缩错误。
- 接口请求格式不符合规范:
account/update_profile_banner.json接口要求所有参数(包括图片内容)通过multipart/form-data格式的POST请求体传递,不支持将图片内容放在URL查询参数中提交。你之前认为直接传二进制体积比base64更大的判断存在误区:二进制内容放在请求体中作为文件域上传时,体积比base64编码小33%左右,是更优的传参方式,你之前的体积判断是基于把二进制内容拼在URL里的错误前提得出的。
修复方案
- 废弃现有
QueryStruct(params)将所有参数拼在URL上的逻辑,所有参数均放在POST请求体中提交。 - 设置请求头
Content-Type为multipart/form-data:- 普通参数(width、height、offset_left、offset_top)作为普通文本表单域传递
- banner参数二选一传递:
- 直接传入图片二进制内容作为文件表单域(推荐,体积更小,无编码开销)
- 传入标准base64编码后的图片字符串作为普通文本表单域
- 提前将横幅图片压缩至官方推荐的1500*500像素,文件大小控制在5MB以内,避免触发服务端上传体积限制。
基于你使用的sling库,修正后的方法实现参考:
import ( "io" "strconv" ) type AccountUpdateProfileBannerPhotoParams struct { Width int `url:"width,omitempty"` Height int `url:"height,omitempty"` OffsetX int `url:"offset_left,omitempty"` OffsetY int `url:"offset_top,omitempty"` } func (s *AccountService) UpdateProfileBannerPhoto(params *AccountUpdateProfileBannerPhotoParams, bannerReader io.Reader) (*User, *http.Response, error) { user := new(User) apiError := new(APIError) // 组装普通表单参数 formFields := map[string]string{ "width": strconv.Itoa(params.Width), "height": strconv.Itoa(params.Height), "offset_left": strconv.Itoa(params.OffsetX), "offset_top": strconv.Itoa(params.OffsetY), } // 构建请求:普通表单+banner文件域 reqBuilder := s.sling.New(). Post("update_profile_banner.json"). BodyForm(formFields). // 第二个参数为自定义文件名,不影响接口校验,第三个参数传入图片二进制流,第四个为图片MIME类型 BodyFile("banner", "profile_banner.jpg", bannerReader, "image/jpeg") resp, err := reqBuilder.Receive(user, apiError) return user, resp, relevantError(err, *apiError) }
如果要使用base64方式传banner,只需要把banner的base64字符串加到formFields里,去掉BodyFile调用即可。
内容的提问来源于stack exchange,提问作者sercan
相关产品推荐
相关产品推荐

