← Назад к вопросам

Как с помощью Retrofit и OkHttp решить задачу добавления header

1.0 Junior🔥 191 комментариев
#Android компоненты#Сетевое взаимодействие

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Реализация добавления заголовков через Retrofit и OkHttp

В экосистеме Retrofit и OkHttp существует несколько гибких способов добавления заголовков к HTTP-запросам. Выбор конкретного подхода зависит от того, нужны ли заголовки для всех запросов или только для конкретных эндпоинтов.

Основные подходы к добавлению заголовков

1. Интерсепторы OkHttp (для глобальных заголовков)

Наиболее мощный и рекомендуемый подход для добавления заголовков, которые должны присутствовать во всех запросах (например, токены аутентификации, версия API).

class AuthInterceptor(private val token: String) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        
        val requestWithHeaders = originalRequest.newBuilder()
            .header("Authorization", "Bearer $token")
            .header("Content-Type", "application/json")
            .header("User-Agent", "MyApp/1.0")
            .build()
        
        return chain.proceed(requestWithHeaders)
    }
}

// Создание клиента OkHttp с интерсептором
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(AuthInterceptor("your_token_here"))
    .build()

// Использование с Retrofit
val retrofit = Retrofit.Builder()
    .baseUrl("https://api.example.com/")
    .client(okHttpClient)
    .addConverterFactory(GsonConverterFactory.create())
    .build()

Преимущества:

  • Централизованное управление заголовками
  • Автоматическое применение ко всем запросам
  • Возможность динамического изменения заголовков

2. Аннотации Retrofit (для конкретных эндпоинтов)

Идеально подходит для заголовков, специфичных для отдельных API-методов.

interface ApiService {
    // Статический заголовок
    @GET("users/profile")
    @Headers("Cache-Control: no-cache")
    suspend fun getUserProfile(): UserProfile
    
    // Динамический заголовок через аннотацию @Header
    @GET("users/{id}")
    suspend fun getUserById(
        @Path("id") userId: String,
        @Header("X-Client-Version") clientVersion: String
    ): User
    
    // Несколько заголовков
    @POST("orders")
    @Headers(
        "Content-Type: application/json",
        "Accept: application/vnd.api+json"
    )
    suspend fun createOrder(@Body order: Order): OrderResponse
}

3. Кастомный Interceptor с условиями

Более продвинутый подход, позволяющий добавлять заголовки на основе условий.

class ConditionalInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        val url = originalRequest.url.toString()
        
        val requestBuilder = originalRequest.newBuilder()
        
        // Добавляем заголовок только для определенных эндпоинтов
        if (url.contains("/secure/")) {
            requestBuilder.header("X-Secure-Request", "true")
        }
        
        // Добавляем временную метку для всех POST-запросов
        if (originalRequest.method == "POST") {
            requestBuilder.header("X-Request-Timestamp", System.currentTimeMillis().toString())
        }
        
        return chain.proceed(requestBuilder.build())
    }
}

4. Аутентификация через Authenticator

Для автоматического обновления токенов аутентификации:

class TokenAuthenticator : Authenticator {
    override fun authenticate(route: Route?, response: Response): Request? {
        return if (responseCount(response) >= 3) {
            null // Слишком много попыток
        } else {
            val newToken = refreshToken() // Ваша логика обновления токена
            
            response.request.newBuilder()
                .header("Authorization", "Bearer $newToken")
                .build()
        }
    }
    
    private fun responseCount(response: Response): Int {
        var count = 1
        var r = response
        while (r.priorResponse != null) {
            count++
            r = r.priorResponse!!
        }
        return count
    }
}

Рекомендации по выбору подхода

  1. Глобальные заголовки (авторизация, версия приложения) → Используйте Interceptor
  2. Специфичные для эндпоинта заголовки → Используйте аннотации @Header или @Headers
  3. Динамические заголовки (зависящие от состояния приложения) → Комбинируйте Interceptor с передачей параметров
  4. Автоматическое обновление токенов → Используйте Authenticator

Пример комплексной реализации

class HeaderManager(private val context: Context) {
    fun createOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(LoggingInterceptor()) // Логирование
            .addInterceptor(AuthInterceptor()) // Авторизация
            .addInterceptor(NetworkInterceptor()) // Проверка сети
            .authenticator(TokenAuthenticator()) // Обновление токенов
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }
}

class AuthInterceptor @Inject constructor(
    private val tokenManager: TokenManager
) : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        
        val newRequest = request.newBuilder().apply {
            tokenManager.getAccessToken()?.let { token ->
                header("Authorization", "Bearer $token")
            }
            header("X-App-Version", BuildConfig.VERSION_NAME)
            header("X-Platform", "Android")
        }.build()
        
        return chain.proceed(newRequest)
    }
}

Ключевые моменты:

  • Интерсепторы выполняются в порядке их добавления
  • Используйте addInterceptor() для запросов и ответов
  • Используйте addNetworkInterceptor() только для сетевых операций
  • Для модификации заголовков в запросах используйте обычные интерсепторы
  • Для обработки 401 ошибок и обновления токенов используйте Authenticator

Такой многоуровневый подход обеспечивает чистую архитектуру, легкую тестируемость и гибкость в управлении HTTP-заголовками в Android-приложении.