Swift/Kotlin对接FileMaker API:Kotlin提交记录令牌无效问题求助
问题背景
我们正在开发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

