Ktor Client调用创建微信小程序二维码接口缺失Content-Length头的坑
本文记录使用Ktor Client调用微信小程序生成二维码接口时遇到的412 Precondition Failed
问题及解决方案。
问题现象
使用Ktor Client的post
方法请求微信生成小程序二维码接口时,服务端返回错误:
HTTP/1.1 412 Precondition Failed
请求头检查发现缺失Content-Length
头,但代码中已明确设置请求体。
问题定位
关键原因 微信接口对Content-Length
请求头有强制校验,而Ktor Client默认配置(使用CIO引擎+Jackson序列化)会启用streamRequestBody=true
。这会采用流式传输导致:
自动省略
Content-Length
头使用
Transfer-Encoding: chunked
验证方式 通过抓包工具(如Wireshark)可见实际请求头:
POST /wxa/getwxacodeunlimit?access_token=TOKEN HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: api.weixin.qq.com
Transfer-Encoding: chunked
解决方案
方案一:手动序列化
实现步骤
使用Jackson手动序列化对象为JSON字符串
指定
Content-Type
为application/json
val httpClient = HttpClient(CIO) {
install(ContentNegotiation) {
jackson()
}
}
suspend fun generateQrCode() {
val requestBody = mapOf(
"path" to "pages/index/index",
"scene" to "id=1"
)
// 手动序列化为JSON字符串
val jsonBody = JsonObjectMapper().writeValueAsString(requestBody)
val response: HttpResponse = httpClient.post("https://api.weixin.qq.com/wxa/getwxacodeunlimit") {
url {
parameter("access_token", accessToken)
}
contentType(ContentType.Application.Json)
setBody(jsonBody)
}
// 处理响应...
}
方案二:禁用流式请求体
实现步骤
配置Jackson的
streamRequestBody
为false
Ktor自动计算并添加
Content-Length
val httpClient = HttpClient(CIO) {
install(ContentNegotiation) {
jackson(contentType = ContentType.Application.Json, streamRequestBody = false) {// 关键配置:禁用流式传输
registerModules(KotlinModule.Builder().build())
configure(SerializationFeature.INDENT_OUTPUT, false)
setSerializationInclusion(JsonInclude.Include.NON_NULL)
}
}
}
suspend fun generateQrCode() {
val requestBody = mapOf(
"path" to "pages/index/index",
"scene" to "id=1"
)
val response: HttpResponse = httpClient.post("https://api.weixin.qq.com/wxa/getwxacodeunlimit") {
url {
parameter("access_token", accessToken)
}
contentType(ContentType.Application.Json)
setBody(requestBody)
}
// 处理响应...
}
总结
HTTP规范注意:对接严格遵循HTTP标准的接口时,要特别注意请求头完整性
Ktor特性:
streamRequestBody=true
适用于大文件传输,但会改变头信息策略灵活选择:根据场景选择手动控制序列化或全局配置,小程序接口推荐方案二
建议在微信生态开发时,使用apifox等工具先验证请求头格式,再移植到代码实现。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 TomSean's Blog
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果