Avatar ·

HTTP POST запрос в Swift: как передать параметры и обработать ответ?

Всем привет! Я новичок в Swift и iOS разработке. Пишу простое приложение для отправки данных на сервер через POST запрос. У меня есть URL и набор параметров (например, логин и пароль), которые нужно отправить. Я пробовал использовать URLSession, но постоянно получаю ошибки или ответ от сервера приходит пустой. Вот мой текущий код: ```swift let url = URL(string: "https://example.com/api/login")! var request = URLRequest(url: url) request.httpMethod = "POST" let parameters = ["username": "test", "password": "12345"] request.httpBody = parameters as? Data let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("Error: \(error)") return } if let data = data { print(String(data: data, encoding: .utf8) ?? "No data") } } task.resume() ``` Проблема в том, что сервер не получает мои параметры или возвращает ошибку 400. Я читал, что нужно сериализовать данные в JSON или использовать form-urlencoded, но не понимаю, как это правильно сделать. Также не уверен насчет обработки ответа — как проверить статус код и распарсить JSON ответ от сервера? Подскажите, пожалуйста, как правильно отправлять 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.