Swift中base64编码字符串上传Frappe时出现填充错误如何解决?
问题原因
- 重复URL编码破坏base64结构:你手动将base64中的
+替换为%2B后,URLQueryItem会自动对参数值做二次URL编码,此时%2B中的%会被编码为%25,服务器解码后得到的是%2B而非原始的+,直接破坏了base64的合法格式。只有当base64内容不含+时不会触发该问题,所以表现为随机复现。 - base64填充规则未正确处理:标准base64要求字符串长度为4的整数倍,末尾缺几位就补几个
=作为填充,你直接拼接固定两个==的方式不符合规范,极端情况下会反而引入额外的填充错误。 - 额外注意:你当前的实现将文件内容全部放在query参数中转为POST body,当文件体积较大时会触发URL长度限制,建议后续改为
multipart/form-data格式上传。
正确处理方案
处理逻辑调整
- 移除手动转码逻辑,
URLQueryItem本身就会自动处理参数中的特殊字符,不需要你手动替换+,避免二次编码问题。 - 按标准规则补全base64填充:计算base64字符串长度对4取模的余数,按需补
=:- 余数为0:不需要补填充
- 余数为2:补1个
= - 余数为3:补2个
=
修改后代码示例
public func attachFileToCloudResource(resourceType: String, resourceName: String, attachment: Data) { // 生成base64并按标准规则补全填充 var base64Str = attachment.base64EncodedString() let remainder = base64Str.count % 4 if remainder != 0 { base64Str += String(repeating: "=", count: 4 - remainder) } var request = URLRequest(url: URL(string: FRAPPE_INSTANCE + FRAPPE_METHODS + FRAPPE_UPLOAD_ATTACHMENT)!) var components = URLComponents(url: request.url!, resolvingAgainstBaseURL: false)! components.queryItems = [ URLQueryItem(name: FRAPPE_DOCTYPE, value: resourceType), URLQueryItem(name: FRAPPE_DOCNAME, value: resourceName), URLQueryItem(name: FRAPPE_FILENAME, value: "testFile.xml"), URLQueryItem(name: FRAPPE_DATA, value: base64Str), URLQueryItem(name: FRAPPE_PRIVATE, value: "1"), URLQueryItem(name: FRAPPE_DECODE_BASE64, value: "1") ] let query = components.url!.query request.httpMethod = "POST" request.addValue("token \(API_KEY):\(API_SECRET)", forHTTPHeaderField: "Authorization") request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpBody = Data(query!.utf8) // 后续请求发送逻辑保持不变 }
如果调整后还是偶现问题,可以在Frappe服务端接收base64参数后,也按上述规则先补全填充再执行解码,前后端双重校验可以彻底解决该类错误。
内容的提问来源于stack exchange,提问作者Andy P
相关产品推荐
相关产品推荐

