Swift Alamofire multipartFormData 400 错误

Swift Alamofire multipartFormData 400 error

提问人:YUNG LEE 提问时间:8/12/2023 最后编辑:YUNG LEE 更新时间:8/12/2023 访问量:69

问:

在此处输入图像描述我尝试通过 Alamofire 发送多部分表单数据。

我一遍又一遍地尝试,但代码出现错误。

我通过 StatusCode 发现这是 400 错误。

下面,按顺序,

服务器接收到的 json 部分(postman),

函数调用部分,

卡片结构部分,

APIClient 部分,

和 CardView 模型部分。

如果你能帮助我,我将不胜感激。

服务器接收到的 json 部分 (postman)

// json
{
    "pTostId": null,
    "userId": 81,
    "createdAt": null,
    "modifiedAt": null,
    "startedAt": "2022-07-29",
    "endedAt": "2023-07-28",
    "title": "시연영상2",
    "memo": "굿",
    "category": "Animation",
    "views": 1,
    "genre": "액션2",
    "platform": "2",
    "emoji": "1",
    "comment": "시연영상 3저장",
    "image": "https://servername-s3.s3.ap-northeast-2.amazonaws.com/4cb5bbf5-064d-4bb2-a7aa-db7cfa999850-Untitled%20design.png"
}

函数调用部分

struct AddCardView: View {
    @ObservedObject var viewModel = CardViewModel.shared

    @State private var image: UIImage? = nil
    @State private var card = Card()

    @State private var isShowingImagePicker = false
    @Environment(\.colorScheme) var colorScheme
    @State private var presentAlert = false
    
    var body: some View {
        VStack(spacing: 20) {
            TextField("Title", text: Binding<String>(
                get: { self.card.title ?? "" },
                set: { self.card.title = $0 }
            ))
                .padding()
                .background(Color.gray.opacity(0.1))
                .cornerRadius(10)

            TextField("Comment", text: Binding<String>(
                get: { self.card.comment ?? "" },
                set: { self.card.comment = $0 }
            ))
                .padding()
                .background(Color.gray.opacity(0.1))
                .cornerRadius(10)

            if let selectedImage = image {
                Image(uiImage: selectedImage)
                    .resizable()
                    .frame(width: 200, height: 200)
            }

            if let image = image {
                Image(uiImage: image)
                    .resizable()
                    .scaledToFill()
                    .frame(width: 280, height: 400)
                    .cornerRadius(20)
                    .clipped()
                    .onTapGesture { // 추가
                        isShowingImagePicker = true
                    }
            } else {
                Image(systemName: "camera") // Default image
                    .resizable()
                    .scaledToFit()
                    .frame(width: 100, height: 250)
                    .onTapGesture {
                        isShowingImagePicker = true
                    }
            }

            Button(action: {
                viewModel.addCard(image: image, with: card)
            }) {
                Text("Add Card")
                    .padding()
                    .background(Color.green)
                    .foregroundColor(.white)
                    .cornerRadius(10)
            }
        }
        .padding()
        .sheet(isPresented: $isShowingImagePicker) {
            ImagePicker(image: $image)
        }
    }
}

卡结构部分

struct Card: Codable, Identifiable {
    var id: Int? { postId }
//    var id = UUID()
    let postId: Int?
    let userId: Int?
    
    var image: String?
    
    var comment: String?
    
    var title: String?
    var emoji: String?
    var platform: String?
    var genre: String?
    var views: Int?
    var memo: String?
    var category: CardCategory?
    
    var createdAt: String?
    var modifiedAt: String?
    var startedAt: String?
    var endedAt: String?
    
    var encodedImageURL: URL? {
        return image?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed).flatMap { URL(string: $0) }
    }
    
//    var page: Int?
    
    // Card에 기본 이니셜라이저를 추가
    init() {
        self.postId = nil
        self.userId = nil

        self.image = nil
        self.comment = nil

        self.title = nil
        self.emoji = nil
        self.platform = nil
        self.genre = nil
        self.views = nil
        self.memo = nil
        self.category = nil

        self.createdAt = nil
        self.modifiedAt = nil
        self.startedAt = nil
        self.endedAt = nil

//        self.page = nil
    }
}

APIClient 部分

    // MARK: -  포토카드 등록
    func addCard(image: UIImage?, with model: Card,  completionHandler: @escaping () -> Void) {
        let url = APIEndpoint.addCardURL
        let header: HTTPHeaders = ["Content-Type": "multipart/form-data"]
        
        let parameters = [
//            "postId": NSNull(),
//            "userId": model.userId,
//            "createdAt": NSNull(),
//            "modifiedAt": NSNull(),
            "startedAt" : model.startedAt ?? "No startedAt",
            "endedAt" : model.endedAt ?? "No endedAt",
            "title" : model.title ?? "No Title",
            "memo" : model.memo ?? "No memo",
            "category" : model.category ?? "Animation",
            "views" : model.views ?? 0,
            "genre" : model.genre ?? "No genre",
            "platform" : model.platform ?? "No platform",
            "emoji" : model.emoji ?? "No emoji",
            "comment" : model.comment ?? "No comment"
        ] as [String : Any]
        
        AF.upload(multipartFormData: { multipartFormData in

            for (key, value) in parameters {
                multipartFormData.append("\(value)".data(using: .utf8)!, withName: key, mimeType: "text/plain")
            }
    
            let imageData = image?.pngData() ?? Data()
            multipartFormData.append(imageData, withName: "image", fileName: "image.png", mimeType: "image/png")
            
        }, to: url, method: .post, headers: header)
        .responseData { response in
            guard let statusCode = response.response?.statusCode else { return }
            switch statusCode {
            case (200...299):
                print("카드 등록 성공")
                completionHandler()
            case (300...399):
                print("Redirection messages")
            case (400):
                print("400")
            case (401...499):
                print("Client error responses")
            case (500...600):
                print("Server error responses")
            default:
                print("카드 등록 실패")
            }
        }
    }

和 CardViewModel 部分

class CardViewModel: ObservableObject {
    
    // MARK: - PROPERTIES
    
    static let shared = CardViewModel() // Singleton instance
    
    @Published var cards: [Card] = []
    @Published var currentCard: Card?


    private init() {}
    
    private var apiClient = APIClient()
    
    
    // MARK: - FUNCTION
    
    func addCard(image: UIImage?, with model: Card) {
        apiClient.addCard(image: image, with: model) {
            DispatchQueue.main.async {
                self.cards.append(model)
                print("Card added successfully!")
            }
        }
    }

谢谢。

我尝试以json的形式尽可能多地将其与图像一起发送到服务器。

我使用状态代码来找出错误是什么。

postId,userId 是在服务器上创建的,因此它不包含在上传中。

终结点结构良好。

Swift Post Alamofire Multipartform-data

评论

0赞 Larme 8/13/2023
您是否需要像这样发送所有参数,还是需要将它们作为一个整体作为 JSON 发送?
0赞 workingdog support Ukraine 8/13/2023
一些观察结果:你在你的 ,但你的 JSON 数据中有 ' “pTostId”: null'。此外,您应该使用 ,不需要单例。尝试使用您的数据,并向我们展示它打印的内容,而不是您认为应该获得的内容。let postId: Int?Card@StateObject var viewModel = CardViewModel()ObservableObjectprint("\(String(data: data, encoding: .utf8)) ")response
0赞 Community 8/13/2023
请修剪您的代码,以便更轻松地找到您的问题。请遵循这些准则,以创建最小的可重现示例

答: 暂无答案