0

我正在尝试将文件作为附件上传到我的 Frappe 实例并遇到了几个问题。第一个是服务器报告填充错误。

我正在尝试将文件(在 iPad 模拟器上)作为数据读取,然后转换为 base64 编码的字符串,然后将其用作我的 httpbody 的一部分。我已经尝试过使用几种不同的文件类型,但出于本示例的目的,我只是使用本地设置文件。

Frappe 实例(有时取决于数据)返回以下错误:

文件 \"/usr/lib/python3.7/base64.py\",第 87 行,在 b64decode\n 返回 binascii.a2b_base64(s)\nbinascii.Error: 不正确的填充

从本地 URL 获取数据:

let settingsLocation = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("SettingsList.plist")
let fileData = try Data.init(contentsOf: settingsLocation)

然后将其传递给以下函数:

    public func attachFileToCloudResource(resourceType: String, resourceName: String, attachment: Data) {
    
    let fileAsString = attachment.base64EncodedString().replacingOccurrences(of: "+", with: "%2B")
    
    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: fileAsString),
        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)


    // Session and dataTask send request below but not relevant to example
    }

经过一番谷歌搜索,我发现我可以通过将“==”附加到文件字符串来解决错误,但这感觉很讨厌/错误。

let fileAsString = (attachment.base64EncodedString().replacingOccurrences(of: "+", with: "%2B") + "==")

有人可以指出我可能会出错的地方以及如何正确地做到这一点吗?

4

1 回答 1

0

我对这个答案并不特别满意,但它是我使用的答案,而且我尝试过的少量 xml 和 pdf 文件对我有用。

从可以解决的问题来看,没有 Swift 方法可以自动生成填充,需要手动完成。

我的解决方案基于这个问题的答案,并为 Data 编写了一个扩展来提供填充:

extension Data {
    
func base64EncodedStringWithPadding() -> String {
    let base64String = self.base64EncodedString()
    let remainder = base64String.count % 4
    if remainder == 0 {
        return base64String
    } else {
        let paddedLength = base64String.count + 4 - remainder
        return base64String.padding(toLength: paddedLength, withPad: "=", startingAt: 0)
    }
    
}
}

然后我在我的函数中使用如下:

let fileAsString = attachment.base64EncodedStringWithPadding()
于 2021-08-19T13:55:46.933 回答