Swift encode URL: 5 фатальных ошибок и как их избежать

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Swift encode URL: почему ваш код ломается на кириллице и пробелах

Каждый разработчик, который хоть раз отправлял сетевой запрос на Swift, сталкивался с этой болью: вы формируете URL, подставляете параметры, а сервер возвращает 400 ошибку или, что еще хуже, — молча игнорирует запрос. Знакомо? Чаще всего проблема кроется в неправильном кодировании URL. Казалось бы, что может быть проще — взял строку, заменил пробелы на %20, и готово. Но Swift (как и любой строгий язык) не прощает халтуры.

В этой статье мы разберем 5 самых распространенных ошибок при Swift encode URL, которые собирают тысячи просмотров на Stack Overflow. Вы узнаете, как их избежать и писать надежный код, который работает с любыми данными — от английских букв до сложной кириллицы и спецсимволов.

Ошибка №1: Использование addingPercentEncoding с неправильным набором символов

Это, пожалуй, самая популярная ловушка. Многие новички видят метод addingPercentEncoding(withAllowedCharacters:) и думают: "О, идеально!". Но передают туда .urlHostAllowed или .urlPathAllowed для всего URL целиком. Результат — краш или некорректный запрос.

Почему это не работает?

Каждая часть URL (схема, хост, путь, query-параметры) имеет свой разрешенный набор символов. Если вы кодируете весь URL как хост, вы потеряете слеши и двоеточия. Если как путь — сломаете query-строку.

// ❌ Ошибка: кодируем весь URL как хост
let urlString = "https://example.com/путь?name=Иван & фамилия=Петров"
let encoded = urlString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
// Результат: "https%3A%2F%2Fexample.com%2F%D0%BF%D1%83%D1%82%D1%8C%3Fname%3D%D0%98%D0%B2%D0%B0%D0%BD%20%26%20%D1%84%D0%B0%D0%BC%D0%B8%D0%BB%D0%B8%D1%8F%3D%D0%9F%D0%B5%D1%82%D1%80%D0%BE%D0%B2"
// Сервер не поймет такой URL

Запомните золотое правило: кодируйте каждую часть URL отдельно или используйте URLComponents.

Правильный подход: URLComponents

// ✅ Правильно: используем URLComponents
var components = URLComponents()
components.scheme = "https"
components.host = "example.com"
components.path = "/путь"
components.queryItems = [
    URLQueryItem(name: "name", value: "Иван & Петров"),
    URLQueryItem(name: "фамилия", value: "Иванов")
]

if let url = components.url {
    print(url.absoluteString)
    // "https://example.com/%D0%BF%D1%83%D1%82%D1%8C?name=%D0%98%D0%B2%D0%B0%D0%BD%20%26%20%D0%9F%D0%B5%D1%82%D1%80%D0%BE%D0%B2&%D1%84%D0%B0%D0%BC%D0%B8%D0%BB%D0%B8%D1%8F=%D0%98%D0%B2%D0%B0%D0%BD%D0%BE%D0%B2"
}

URLComponents автоматически применяет правильное percent encoding для каждого компонента. Это избавляет вас от головной боли и делает код чище.

Ошибка №2: Игнорирование queryItems в пользу ручной сборки строки

"Зачем мне эти ваши компоненты? Я просто склею строку через +". Знакомая мысль? И это ведет ко второй популярной ошибке. Ручная сборка query-строки — прямой путь к багам.

// ❌ Ошибка: ручная сборка query-строки
let name = "Иван & Петров"
let query = "name=\(name)&age=25"
let urlString = "https://example.com?\(query)"
// Проблема: амперсанд в имени будет воспринят как разделитель параметров

Даже если вы замените пробелы, вы забудете про &, #, ? и другие спецсимволы. А если параметр придет от пользователя? Ждите инъекций и сломанных запросов.

Решение: всегда используйте queryItems

// ✅ Правильно: queryItems делает всю работу за вас
var components = URLComponents(string: "https://example.com")!
components.queryItems = [
    URLQueryItem(name: "name", value: "Иван & Петров"),
    URLQueryItem(name: "age", value: "25"),
    URLQueryItem(name: "q", value: "Swift encode URL tutorial")
]

if let url = components.url {
    print(url.absoluteString)
    // name=Иван%20%26%20Петров&age=25&q=Swift%20encode%20URL%20tutorial
}

Этот подход гарантирует корректное URL encoding Swift для всех параметров. Вы просто передаете сырые значения, а система сама решает, какие символы нужно экранировать.

Ошибка №3: Забываем про кодирование пути (path)

Третья ошибка — когда разработчики кодируют query-параметры, но забывают про путь. Кириллица в пути — частая причина 404 ошибок.

// ❌ Ошибка: кириллица в пути без кодирования
let url = URL(string: "https://example.com/каталог/товар?id=1")
// nil! URL инициализатор вернет nil, так как строка невалидна

Swift строг: если в строке есть недопустимые символы, URL(string:) вернет nil. И ваше приложение либо упадет, либо тихо ничего не сделает.

Решение: кодируем путь отдельно

// ✅ Правильно: кодируем путь через addingPercentEncoding
let path = "/каталог/товар"
let encodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "/"
// encodedPath = "/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3/%D1%82%D0%BE%D0%B2%D0%B0%D1%80"

var components = URLComponents()
components.scheme = "https"
components.host = "example.com"
components.path = encodedPath
components.queryItems = [URLQueryItem(name: "id", value: "1")]

if let url = components.url {
    print(url.absoluteString)
    // "https://example.com/%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3/%D1%82%D0%BE%D0%B2%D0%B0%D1%80?id=1"
}

Обратите внимание: .urlPathAllowed разрешает слеши, поэтому структура папок сохраняется. Но если у вас в названии товара есть слеш — он тоже будет закодирован, что правильно.

Ошибка №4: Двойное кодирование (double encoding)

Самая коварная ошибка. Вы уже закодировали URL, передали его в функцию, а та кодирует его снова. В результате %20 превращается в %2520, сервер получает мусор.

// ❌ Ошибка: двойное кодирование
let original = "Swift encode URL"
let                

Блоги

Рекомендаций по книгам