HTTP POST запрос в Swift: как передать параметры и обработать ответ?
Правильная отправка POST запроса с параметрами в Swift
Ваша основная ошибка — некорректная передача параметров. Параметры нужно сериализовать в формат, который ожидает сервер. Чаще всего это JSON или form-urlencoded. Рассмотрим оба варианта с полной обработкой ответа.
Вариант 1: JSON (самый распространённый)
Большинство современных API принимают JSON. Используйте JSONSerialization или JSONEncoder.
import Foundation
func sendPostRequest() {
// 1. Создаём URL и запрос
guard let url = URL(string: "https://example.com/api/login") else {
print("Invalid URL")
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
// 2. Устанавливаем заголовок Content-Type
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
// 3. Подготавливаем параметры
let parameters: [String: Any] = [
"username": "test",
"password": "12345"
]
// 4. Сериализуем в JSON
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: [])
} catch {
print("JSON serialization error: \(error.localizedDescription)")
return
}
// 5. Отправляем запрос
let task = URLSession.shared.dataTask(with: request) { data, response, error in
// 6. Проверяем ошибки сети
if let error = error {
print("Network error: \(error.localizedDescription)")
return
}
// 7. Проверяем HTTP статус код
guard let httpResponse = response as? HTTPURLResponse else {
print("Invalid response")
return
}
print("Status code: \(httpResponse.statusCode)")
guard (200...299).contains(httpResponse.statusCode) else {
print("Server error with status code: \(httpResponse.statusCode)")
// Можно прочитать тело ответа для диагностики
if let data = data {
let body = String(data: data, encoding: .utf8) ?? "No body"
print("Response body: \(body)")
}
return
}
// 8. Обрабатываем успешный ответ
guard let data = data else {
print("No data received")
return
}
do {
// Декодируем JSON (предположим, что сервер возвращает словарь)
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
print("Response JSON: \(json)")
// Извлекаем нужные поля
if let token = json["token"] as? String {
print("Token: \(token)")
}
}
} catch {
print("JSON parsing error: \(error.localizedDescription)")
// Попробуем прочитать как строку
print("Raw response: \(String(data: data, encoding: .utf8) ?? "")")
}
}
task.resume()
}
// Вызов функции
sendPostRequest()
Вариант 2: Form-URLEncoded (для старых API)
Некоторые серверы ожидают данные в формате application/x-www-form-urlencoded.
func sendFormURLEncodedRequest() {
guard let url = URL(string: "https://example.com/api/login") else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let parameters = ["username": "test", "password": "12345"]
// Создаём строку параметров
let parameterArray = parameters.map { (key, value) -> String in
// URL-кодируем ключи и значения
let encodedKey = key.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? key
let encodedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "\(value)"
return "\(encodedKey)=\(encodedValue)"
}
let bodyString = parameterArray.joined(separator: "&")
request.httpBody = bodyString.data(using: .utf8)
// Далее тот же код с dataTask...
}
Рекомендации для начинающих
- Всегда проверяйте статус код — 200-299 означает успех, 400+ — ошибка клиента/сервера
- Не забывайте про заголовки — Content-Type обязателен для POST
- Используйте async/await — современный способ (Swift 5.5+):
func sendPostAsync() async throws {
let url = URL(string: "https://example.com/api/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let parameters = ["username": "test", "password": "12345"]
request.httpBody = try JSONSerialization.data(withJSONObject: parameters)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw URLError(.badServerResponse)
}
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
print(json)
}
}
// Вызов в Task
Task {
do {
try await sendPostAsync()
} catch {
print(error)
}
}
Эти примеры покрывают 90% случаев. Если сервер всё равно не принимает данные — проверьте документацию API, возможно нужны дополнительные заголовки (например, авторизация) или специфический формат.
<<Альтернативный подход: использование библиотеки Alamofire
Если вы часто работаете с сетевыми запросами и хотите упростить код, рекомендую использовать популярную библиотеку Alamofire. Она значительно сокращает шаблонный код и обрабатывает множество деталей автоматически.
Установка через Swift Package Manager: добавьте пакет https://github.com/Alamofire/Alamofire.git.
Пример POST запроса с Alamofire:
import Alamofire
let parameters: [String: Any] = [
"username": "test",
"password": "12345"
]
AF.request("https://example.com/api/login",
method: .post,
parameters: parameters,
encoding: JSONEncoding.default)
.validate() // автоматически проверяет статус код
.responseJSON { response in
switch response.result {
case .success(let value):
print("Success: \(value)")
// value — это уже распарсенный JSON (Any)
if let json = value as? [String: Any] {
print(json["token"] ?? "")
}
case .failure(let error):
print("Error: \(error.localizedDescription)")
// response.data содержит тело ответа при ошибке
if let data = response.data {
print(String(data: data, encoding: .utf8) ?? "")
}
}
}
Плюсы Alamofire:
- Автоматическая сериализация параметров в JSON или URL-encoded
- Встроенная валидация ответов
- Удобная обработка ошибок
- Поддержка загрузки файлов, прогресс-баров, повторных попыток
Однако для простых проектов или обучения лучше сначала освоить нативный URLSession — это даст глубокое понимание работы сети в iOS.
Ответов пока нет.
Войдите чтобы оставить ответ