iOS 端使用 AFNetworking 發送請求,Spring MVC 後端無法接收參數(@RequestParam 綁定失敗、@RequestBody 為空)。
application/x-www-form-urlencoded 或 multipart/form-data 發送,而 Spring MVC REST 風格預期 application/json。@ModelAttribute 或表單轉換器,無法自動映射至 POJO。HTTPMethod 並處理 _method 參數。| 方案 | 修改成本 | 相容性 | 推薦度 |
|---|---|---|---|
Spring MVC 增加 FormHttpMessageConverter、@ModelAttribute | 低 | 良好 | ⭐⭐⭐ |
iOS 改用 JSONSerialization + 設定 Content-Type: application/json | 中 | 最佳 | ⭐⭐⭐⭐⭐ |
| 遷移至 Alamofire / URLSession 原生 + Codable (Swift) | 高(重寫網路層) | 現代標準 | ⭐⭐⭐⭐ |
// Swift 5 + URLSession + Codable
struct LoginRequest: Codable { let username: String; let password: String }
struct LoginResponse: Codable { let token: String; let userId: Int }
func login(username: String, password: String, completion: @escaping (Result<LoginResponse, Error>) -> Void) {
let url = URL(string: \"https://api.example.com/auth/login\")!
var request = URLRequest(url: url)
request.httpMethod = \"POST\"
request.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")
request.httpBody = try? JSONEncoder().encode(LoginRequest(username: username, password: password))
URLSession.shared.dataTask(with: request) { data, resp, err in
if let err = err { completion(.failure(err)); return }
guard let data = data,
let httpResp = resp as? HTTPURLResponse,
(200..<300).contains(httpResp.statusCode) else {
completion(.failure(NSError(domain: \"\", code: -1, userInfo: [NSLocalizedDescriptionKey: \"Invalid response\"])))
return
}
do { completion(.success(try JSONDecoder().decode(LoginResponse.self, from: data))) }
catch { completion(.failure(error)) }
}.resume()
}
@PostMapping(\"/auth/login\")
public ResponseEntity<LoginResponse> login(@RequestBody LoginRequest request) {
// 驗證邏輯
return ResponseEntity.ok(new LoginResponse(token, userId));
}
AFNetworking 適合傳統表單型 API,對於 RESTful JSON API,iOS 原生 URLSession + Codable 或 Alamofire 5+ 是更現代、穩健的選擇,避免序列化與 Content-Type 不匹配的坑。