Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

+1 661новая вакансия за сутки·92 296вакансий открыто сейчас·Новое:Talanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Новые вакансии в TelegramРаботодателям
Talanto
Вакансии
Компании7 192
РезюмеAIПодготовкаСтатьи
BoostТарифыBoost
Войти

Не нашли подходящее?

Пусть нужная вакансия найдёт вас сама.

  1. Подборка в TelegramНовые вакансии по вашему фильтру — сразу в бота.Подключить
  2. Мэтчи по резюмеЗагрузите резюме — покажем, где вы подходите лучше всего.Загрузить
  3. Сохранить фильтрНастройте поиск один раз и возвращайтесь к новым вакансиям.Настроить
Что нового на TalantoTalanto осенью: поиск с цифрами, вакансия по шагам и каталог компаний

Для работодателей

Опубликуйте вакансию — отклики придут в ваш кабинет.

  1. Вакансиябесплатно
  2. Откликиконтакты бесплатно
  3. Наймэтапы и интервью

40 компаний публикуют вакансии напрямую · 4 401 кандидат открыт к предложениям

Разместить вакансию

Популярные направления

Все подборки
  • Python17 143
  • Облачные технологии14 064
  • QA вакансии3 446
  • Backend вакансии2 095
  • Инженер данных1 792
  • Продакт-менеджер1 233

Разработка

  • Android1 857
  • iOS1 697
  • Fullstack вакансии981
  • AI вакансии949
  • Frontend вакансии742
  • Mobile вакансии44

По стеку

  • Go8 689
  • Java6 529
  • Node.js2 023
  • .NET1 723
  • Kotlin1 596
  • Rust1 462
  • C#710
  • PHP683
  • C++574

DevOps и инфраструктура

  • Kubernetes7 762
  • DevOps вакансии6 052
  • Linux-инфраструктура5 491
  • Terraform / IaC4 268
  • CI/CD3 244
  • Мониторинг и Observability1 789
  • SRE567
  • Кибербезопасность455

Аналитика и данные

  • Data Scientist1 124
  • Бизнес-аналитик917
  • Аналитик данных839
  • Системный аналитик151

Другие направления

  • Проджект-менеджер606
  • UI/UX дизайн142
  • Ручное тестирование14

По регионам

  • Вакансии в США43 473
  • Вакансии в Европе23 552
  • Вакансии в Канаде4 444
  • Работа в России3 901

По формату

  • Удалённые вакансии73 579
  • Релокация в США43 516
  • Гибридная работа12 395
  • Офисная работа7 085

По уровню

  • Senior вакансии42 222
  • Middle вакансии20 589
  • Junior вакансии6 639

Сейчас нанимают

Все компании
  • Wise190 вакансий
  • Rakuten189 вакансий
  • ASML166 вакансий
  • Grab137 вакансий
  • Celonis39 вакансий
  • Spotify37 вакансий
  • Adyen28 вакансий
  • Infobip28 вакансий
  • Monzo20 вакансий
  • Darktrace16 вакансий

Вакансии из 344 источников: карьерные страницы компаний и джоб-борды.

КомпанииО насНовостиПубличная офертаУсловия использованияПолитика конфиденциальностиПоддержка
←К теме KtorВсе вопросы
KtorMiddleТеория

Как Ktor поддерживает загрузку файлов через multipart?

В закладки
Сначала попробуйте ответить сами30 секунд
Сравнить с ответом ↓

Ktor обрабатывает multipart/form-data через call.receiveMultipart(). Метод возвращает MultiPartData, по которому итерируются части: PartData.FormItem для текста и PartData.FileItem для файлов.

Зависимости

// build.gradle.kts
dependencies {
    val ktor_version = "2.3.12"
    // multipart поддерживается в ядре, дополнительных зависимостей не нужно
    implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
    implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
    // для работы с файловой системой
    implementation("org.jetbrains.kotlinx:kotlinx-io-core:0.4.0")
}

Базовая обработка загрузки файла

import io.ktor.http.content.*
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import java.io.File

fun Application.configureUpload() {
    routing {
        post("/upload") {
            val multipart = call.receiveMultipart()
            var fileName = ""
            var savedPath = ""

            multipart.forEachPart { part ->
                when (part) {
                    is PartData.FormItem -> {
                        // Текстовое поле формы
                        println("Field '${part.name}' = ${part.value}")
                    }
                    is PartData.FileItem -> {
                        fileName = part.originalFileName ?: "upload_${System.currentTimeMillis()}"
                        val uploadDir = File("uploads").also { it.mkdirs() }
                        val destFile = File(uploadDir, fileName)
                        part.streamProvider().use { input ->
                            destFile.outputStream().use { output ->
                                input.copyTo(output)
                            }
                        }
                        savedPath = destFile.absolutePath
                    }
                    else -> {}
                }
                part.dispose() // ОБЯЗАТЕЛЬНО освобождать ресурсы
            }

            call.respond(mapOf(
                "fileName" to fileName,
                "path" to savedPath,
                "status" to "uploaded"
            ))
        }
    }
}

Ограничение размера файла

import io.ktor.server.plugins.requestvalidation.*

fun Application.configureUploadWithLimit() {
    // Ограничение через конфигурацию Netty
    install(io.ktor.server.netty.NettyApplicationEngine) {}
    // Либо через middleware:
    routing {
        post("/upload-limited") {
            val contentLength = call.request.contentLength() ?: 0L
            val maxSize = 10 * 1024 * 1024L // 10 MB
            if (contentLength > maxSize) {
                call.respond(HttpStatusCode.PayloadTooLarge, "File too large")
                return@post
            }
            val multipart = call.receiveMultipart()
            multipart.forEachPart { part ->
                if (part is PartData.FileItem) {
                    val bytes = part.streamProvider().readBytes()
                    if (bytes.size > maxSize) {
                        call.respond(HttpStatusCode.PayloadTooLarge)
                        return@forEachPart
                    }
                    // сохраняем bytes
                }
                part.dispose()
            }
            call.respond(HttpStatusCode.OK)
        }
    }
}

Загрузка нескольких файлов

post("/upload-multiple") {
    val multipart = call.receiveMultipart()
    val uploadedFiles = mutableListOf<String>()

    multipart.forEachPart { part ->
                if (part is PartData.FileItem) {
            val name = part.originalFileName ?: "file_${uploadedFiles.size}"
            val dest = File("uploads/$name")
            part.streamProvider().use { it.copyTo(dest.outputStream()) }
            uploadedFiles.add(name)
        }
        part.dispose()
    }
    call.respond(mapOf("uploaded" to uploadedFiles))
}

Подводные камни

  • Вызов part.dispose() обязателен для каждой части — утечка без него приводит к исчерпанию памяти под нагрузкой.
  • originalFileName — значение из заголовка Content-Disposition, которое приходит от клиента; никогда не используйте его как путь к файлу без санитизации (path traversal атака).
  • Метод forEachPart читает тело лениво — повторный вызов receiveMultipart() вернёт пустой поток.
  • При использовании nginx как reverse-proxy нужно задать client_max_body_size — иначе nginx обрежет запрос до того, как Ktor его получит.
  • streamProvider() возвращает поток, который может быть прочитан только один раз; сохраняйте содержимое сразу.
  • Для очень больших файлов readBytes() загрузит всё в RAM; используйте потоковую запись через copyTo().
  • Content-Type multipart/form-data без boundary в заголовке вызовет исключение при receiveMultipart().

Частые вопросы на собеседовании

  • Какие security-риски возникают в Ktor при CORS, JWT/session auth и обработке multipart-загрузок?
  • Каковы варианты production-деплоя приложения Ktor?
  • Как определять маршруты (routes) в Ktor и как работает вложенная маршрутизация?
  • Что такое plugins (ранее features) в Ktor и как их устанавливать?

Типичные ошибки

  • Путать термин «multipart upload» с соседним механизмом Ktor.
  • Не называть границу lifecycle, transaction, thread или request для «multipart upload».
  • Игнорировать production-эффекты «multipart upload»: latency, SQL shape, memory, security или observability.

Что проверяет интервьюер

  • Попросить объяснить механизм «multipart upload» на минимальном примере.
  • Проверить, видит ли кандидат failure mode и диагностику для «multipart upload».
  • Уточнить, какие настройки или API меняют «multipart upload» в реальном сервисе.

Как вы знаете этот вопрос?

Проверить себя по теме Ktor →

Источники

  • https://ktor.io/docs/server-requests.html
←Предыдущий вопросКак обрабатывать ошибки и исключения глобально в Ktor с помощью `StatusPages`?Следующий вопрос→Что такое Ktor engines и в чём разница между CIO, Netty и Jetty?

Связанные темы

Ktorbackend-designktortechnical-communication