将OkHttpClient转换为Retrofit 2:上传文件遇403 Forbidden问题排查
Alright, let's break down why your Retrofit 2 setup is hitting a FORBIDDEN error when your original code worked perfectly. Since the API accepts a byte array for text file uploads, here are the key areas to check, with actionable fixes:
Mismatched Request Headers
FORBIDDEN errors often boil down to missing or incorrect headers. Double-check that your Retrofit implementation includes exactly the same headers as your working Part 1 code—things likeAuthorizationtokens,Content-Type, or custom API keys are easy to miss.For example, if your API expects
application/octet-streamfor byte array uploads and a Bearer token, your Retrofit interface should look like this:interface FileUploadService { @Headers("Content-Type: application/octet-stream") @POST("your-upload-endpoint") suspend fun uploadTextFile( @Header("Authorization") authToken: String, @Body fileBytes: ByteArray ): Response<UploadResult> }Pro tip: Compare the full header list from your working code (use tools like OkHttp logging) to what Retrofit is sending—even a typo in a header name can trigger 403.
Incorrect RequestBody Handling
While Retrofit can automatically convert aByteArrayto a request body, sometimes the API expects a specificRequestBodyconfiguration that your original code used. If your Part 1 code explicitly built aRequestBodywith a media type, replicate that in Retrofit:// Build the request body exactly like your Part 1 code val mediaType = MediaType.parse("application/octet-stream") val requestBody = RequestBody.create(mediaType, fileBytes) // Update your Retrofit interface to accept RequestBody instead of ByteArray interface FileUploadService { @POST("your-upload-endpoint") suspend fun uploadTextFile( @Header("Authorization") authToken: String, @Body requestBody: RequestBody ): Response<UploadResult> }Authentication Token Issues
This is the most common culprit for 403s. Verify:- Your token is not expired (check its validity against the API's auth rules)
- You're using the correct format (e.g., don't forget the
Bearerprefix if required) - The token is being added to every Retrofit request. If your Part 1 code used an OkHttp interceptor to inject tokens, make sure your Retrofit
OkHttpClientuses the same interceptor:val okHttpClient = OkHttpClient.Builder() .addInterceptor { chain -> val originalRequest = chain.request() val authenticatedRequest = originalRequest.newBuilder() .header("Authorization", "Bearer ${yourValidToken}") .build() chain.proceed(authenticatedRequest) } .build() val retrofit = Retrofit.Builder() .baseUrl(API_BASE_URL) .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build()
Base URL/Endpoint Path Discrepancies
A tiny mismatch in your base URL or endpoint path can send requests to the wrong endpoint, which might return 403 due to permissions. For example:- If your Part 1 code uses
https://api.example.com/v1/upload, ensure Retrofit's base URL ishttps://api.example.com/v1/and the endpoint is@POST("upload")(not@POST("/upload"), which would drop the/v1segment).
Use OkHttp's logging interceptor to inspect the full request URL and confirm it matches your working code:
val loggingInterceptor = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY // Logs headers, body, and URL } val okHttpClient = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build()- If your Part 1 code uses
Mismatched Byte Array Content
Even if you're sending a byte array, differences in how you read the text file can change the content. For example, if your Part 1 code reads the file with UTF-8 encoding, ensure Retrofit uses the same method:// Read the text file exactly like your Part 1 code val file = File("path/to/your/textfile.txt") val fileBytes = file.readText(Charsets.UTF_8).toByteArray(Charsets.UTF_8)Compare the byte array length or a sample of the bytes between your two implementations to rule out content differences.
OkHttpClient Configuration Gaps
If your Part 1 code uses custom OkHttp settings (like timeouts, SSL certificates, or proxies), your Retrofit client must mirror those. For example, if the API requires a specific SSL certificate pinning setup, missing that in Retrofit can lead to a 403.
内容的提问来源于stack exchange,提问作者user1154390

