You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift/Kotlin对接FileMaker API:Kotlin提交记录令牌无效问题求助

Kotlin调用FileMaker Data API提交记录时令牌无效(Swift正常)

问题背景

我们正在开发iOS(Swift)和Android(Kotlin)双端应用,从蓝牙设备收集数据后提交至FileMaker 18数据库。FileMaker Data API要求先通过POST请求获取会话令牌authToken,再使用该令牌提交数据记录。

Swift端两个请求均正常工作,但Kotlin端仅获取令牌的请求成功,提交记录时持续返回错误:

{"messages":[{"code":"952","message":"Invalid FileMaker Data API token (*)"}],"response":{}}

关键现象:

  • Kotlin生成的authToken在Swift中可以正常用于提交记录,说明令牌本身有效
  • Kotlin中两个请求的构建逻辑看似一致,但提交请求始终失败

代码对比

Swift 代码

获取令牌(getAuth())

let url = URL(string: "https://<host>/fmi/data/vLatest/databases/<DB>/sessions")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Basic <login>", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"

响应:

{"response":{"token":"<authToken>"},"messages":[{"code":"0","message":"OK"}]}

提交记录(postToFM())

let url = URL(string: "https://<host>/fmi/data/vLatest/databases/<DB>/layouts/POSTin/records")!
var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer " + authToken, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"

响应:

["messages": <__NSSingleObjectArrayI 0x28169b760>({code = 0;message = OK;}),"response":{modId = 0;recordId = <number>;}]

Kotlin 代码

获取令牌(getAuth())

val url = URL("https://<host>/fmi/data/vLatest/databases/<DB>/sessions")
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"
conn.doOutput = true
conn.useCaches = false
conn.setRequestProperty("Authorization", "Basic *login*")
conn.setRequestProperty("Content-Type", "application/json")

响应:

{"response":{"token":"<authToken>"},"messages":[{"code":"0","message":"OK"}]}

提交记录(postToFM())

val url = URL("https://<host>/fmi/data/vLatest/databases/<DB>/layouts/POSTin/records")
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"
conn.doOutput = true
conn.doInput = true
conn.useCaches = false
conn.setRequestProperty("Authorization", "Bearer $authToken")
conn.setRequestProperty("Content-Type", "application/json")
conn.setRequestProperty("Content-Length", fieldData.length.toString())

响应:

{"messages":[{"code":"952","message":"Invalid FileMaker Data API token (*)"}],"response":{}}

排查与解决方案

1. 验证Authorization头的空格格式

Swift中明确在Bearer和令牌之间添加了空格,Kotlin中使用"Bearer $authToken"拼接时,需确保Bearer后有且仅有一个空格,且令牌本身没有多余的前导/尾随空白。可以打印完整的Authorization头确认:

val authHeader = "Bearer $authToken"
println("Authorization Header: '$authHeader'") // 用单引号包裹便于查看空白
conn.setRequestProperty("Authorization", authHeader)

2. 移除手动设置的Content-Length

Kotlin代码中手动设置Content-Length可能导致字节数计算错误(比如字符串长度和UTF-8编码后的字节数不一致),进而引发请求体解析异常,连带令牌验证失败。建议让HttpURLConnection自动处理:

// 移除该行代码
// conn.setRequestProperty("Content-Length", fieldData.length.toString())

3. 检查令牌是否包含多余字符

从JSON响应中解析authToken时,可能意外包含引号、换行符或空白字符。打印令牌的长度和内容,对比Swift端解析的结果:

println("AuthToken Length: ${authToken.length}")
println("AuthToken Content: '$authToken'")

如果存在多余字符,需在解析时去除(比如使用trim()或JSON库正确解析字符串)。

4. 确认请求头未被覆盖

检查是否有全局配置或拦截器修改了请求头,可在设置完所有请求头后打印全部请求头:

conn.requestProperties.forEach { (key, value) ->
    println("$key: $value")
}

5. 确保请求体编码一致

发送请求体时指定UTF-8编码,和Swift端保持一致:

val outputStream = conn.outputStream
outputStream.write(fieldData.toByteArray(Charsets.UTF_8))
outputStream.flush()
outputStream.close()

内容的提问来源于stack exchange,提问作者Heidi Brinkley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 16:45:46