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

Swift新手求助:iOS本地PDF/DOCX/图片上传服务器失败(415错误)

Swift上传文件遇到415错误?看这里!

嘿,作为Swift新手碰到这个问题太正常啦!415状态码说白了就是服务器在喊“我看不懂你发过来的内容格式啊!”,大概率是你请求的Content-Type没设置对,或者上传文件的表单数据构造出了问题。下面给你一步步解决:

核心原因分析

415(Unsupported Media Type)通常出现在这几种情况:

  • 没有用multipart/form-data格式上传文件(这是文件上传的标准格式)
  • 请求头的Content-Type没带正确的边界字符串(boundary)
  • 文件的MIME类型和服务器期望的不匹配(比如把PDF标成了image/jpeg)

修正后的完整代码示例

先给你把代码改好,你可以直接参考:

import UIKit
import MobileCoreServices // 要导入这个框架来获取MIME类型

func uploadFileToServer(completed: @escaping () -> ()) {
    guard let theTitle = labelTitle.text, !theTitle.isEmpty else {
        print("标题不能为空")
        completed()
        return
    }
    guard let url = URL(string: "http://www.--------.com/assignment/post") else {
        print("无效的服务器URL")
        completed()
        return
    }
    // 假设你已经拿到了要上传的本地文件URL,这里替换成你自己的文件获取逻辑
    guard let fileURL = getLocalFileURL() else {
        print("找不到本地文件")
        completed()
        return
    }
    
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    
    // 1. 设置正确的请求头
    let boundary = "Boundary-\(UUID().uuidString)" // 生成随机边界字符串
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    // 如果服务器需要授权token,把你的token加上
    request.setValue("cf7ab8c9d4efae82b575...", forHTTPHeaderField: "Authorization")
    
    // 2. 构造multipart表单数据
    var body = Data()
    
    // 添加标题参数(如果服务器需要的话)
    body.append("--\(boundary)\r\n".data(using: .utf8)!)
    body.append("Content-Disposition: form-data; name=\"title\"\r\n\r\n".data(using: .utf8)!)
    body.append("\(theTitle)\r\n".data(using: .utf8)!)
    
    // 添加文件数据
    do {
        let fileData = try Data(contentsOf: fileURL)
        let fileName = fileURL.lastPathComponent
        let mimeType = getMimeType(for: fileURL)
        
        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\(fileName)\"\r\n".data(using: .utf8)!)
        body.append("Content-Type: \(mimeType)\r\n\r\n".data(using: .utf8)!)
        body.append(fileData)
        body.append("\r\n".data(using: .utf8)!)
    } catch {
        print("读取本地文件失败:\(error.localizedDescription)")
        completed()
        return
    }
    
    // 结束表单边界
    body.append("--\(boundary)--\r\n".data(using: .utf8)!)
    request.httpBody = body
    
    // 3. 发起请求
    let task = URLSession.shared.dataTask(with: request) { data, response, error in
        defer { completed() } // 不管成功失败都调用完成回调
        
        if let error = error {
            print("请求出错:\(error.localizedDescription)")
            return
        }
        
        guard let httpResponse = response as? HTTPURLResponse else {
            print("无效的服务器响应")
            return
        }
        
        print("响应状态码:\(httpResponse.statusCode)")
        if let data = data, let responseStr = String(data: data, encoding: .utf8) {
            print("服务器返回内容:\(responseStr)")
        }
    }
    task.resume()
}

// 辅助函数:获取本地文件URL(替换成你自己的文件选择逻辑,比如UIImagePickerController获取的URL)
func getLocalFileURL() -> URL? {
    // 示例:这里只是模拟,你需要替换成实际的文件获取代码
    let documentsDir = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
    return URL(fileURLWithPath: documentsDir).appendingPathComponent("test.pdf")
}

// 辅助函数:获取文件的MIME类型
func getMimeType(for fileURL: URL) -> String {
    if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, fileURL.pathExtension as CFString, nil)?.takeRetainedValue() {
        if let mimeType = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() {
            return mimeType as String
        }
    }
    // 如果识别不出来,默认返回二进制流类型
    return "application/octet-stream"
}

关键注意点

  • 必须用multipart/form-data格式:上传文件绝对不能用application/json这类格式,服务器根本识别不了文件内容
  • 边界字符串要唯一:用UUID生成的边界能避免和文件内容冲突,确保服务器能正确拆分表单部分
  • MIME类型要准确:不同文件类型对应不同的MIME,比如:
    • PDF: application/pdf
    • DOCX: application/vnd.openxmlformats-officedocument.wordprocessingml.document
    • JPG: image/jpeg
    • PNG: image/png
  • 参数要放在表单里:如果服务器需要标题、用户ID这类参数,一定要加到multipart表单中,不能直接拼在URL或者用JSON传

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:20:10