如何在Retrofit中发送含多类型参数及图片的Multipart请求?
Retrofit Multipart Form Request with Mixed Data Types & File Attachment: Fixes & Best Practices
Let's walk through your implementation and fix the key issues that might be causing problems with your multipart request:
1. Core Issues in Current Code
- Raw Int/Boolean @Part Parameters: Retrofit doesn’t handle raw primitive types (like
Int,Boolean) directly in@Multipartrequests. These need to be wrapped intoRequestBodyto ensure proper form-data serialization. - Incorrect MediaType for String Fields: Using
multipart/form-datafor regular string fields is unnecessary;text/plainis the appropriate media type for simple text values. - Potential File Path Mistake: When creating the image part, make sure
imageFilePathis aFileinstance (not just a string path) – your code referencesstore.imagePathFile?.name, so double-check the file object is valid.
2. Corrected Retrofit Interface
@Multipart @POST(AppConstants.Network.CREATE_STORE) fun createStore( @Header("Authorization") token: String, // Image part (nullable if optional) @Part imagePath: MultipartBody.Part?, // String fields wrapped in RequestBody @Part("Name") storeName: RequestBody, @Part("StoreOwnerName") storeOwnerName: RequestBody, @Part("StoreOwnerGender") storeOwnerGender: RequestBody, @Part("StoreOwnerDob") storeOwnerDob: RequestBody, @Part("AddressLine1") addressLine1: RequestBody, @Part("AddressLine2") addressLine2: RequestBody, @Part("AddressLine3") addressLine3: RequestBody, @Part("Place") place: RequestBody, @Part("PinCode") pinCode: RequestBody, // Changed from Int to RequestBody @Part("ContactNumber") contactNumber: RequestBody, @Part("Email") email: RequestBody, // Boolean fields wrapped in RequestBody @Part("IsRegistered") isRegistered: RequestBody, // Changed from Boolean to RequestBody @Part("HasGst") hasGst: RequestBody, // Changed from Boolean to RequestBody @Part("GSTNumber") GSTNumber: RequestBody, // Changed from Int to RequestBody @Part("HasInsurance") hasInsurance: RequestBody, // Changed from Boolean to RequestBody @Part("HasBankAccount") hasBankAccount: RequestBody, // Changed from Boolean to RequestBody // Int fields wrapped in RequestBody @Part("StaffSize") staffSize: RequestBody, // Changed from Int to RequestBody @Part("StoreSize") storeSize: RequestBody, // Changed from Int to RequestBody @Part("RunningFrom") runningFromDate: RequestBody, @Part("StoreTypeId") storeTypeId: RequestBody, // Changed from Int to RequestBody @Part("AverageTurnOver") averageTurnOver: RequestBody, // Changed from Int to RequestBody @Part("OwnerResponseId") ownerResponseId: RequestBody, // Changed from Int to RequestBody @Part("Remarks") remarks: RequestBody ): Single<ResponseBody>
3. Corrected API Call Implementation
// Helper functions to reduce code duplication fun createTextRequestBody(value: String): RequestBody { return RequestBody.create(MediaType.parse("text/plain"), value) } fun createPrimitiveRequestBody(value: Any): RequestBody { return RequestBody.create(MediaType.parse("text/plain"), value.toString()) } // Usage in your call apiService.createStore( token = "bearer ${AppPreferences(context!!).token!!}", imagePath = store.imagePathFile?.let { imageFile -> MultipartBody.Part.createFormData( name = "ImagePath", filename = imageFile.name, body = RequestBody.create(MediaType.parse("image/*"), imageFile) ) }, // Safely handle nullable file storeName = createTextRequestBody("Your Name"), storeOwnerName = createTextRequestBody("Your Name"), storeOwnerGender = createTextRequestBody("Your Name"), storeOwnerDob = createTextRequestBody("Your Name"), addressLine1 = createTextRequestBody("Your Name"), addressLine2 = createTextRequestBody("Your Name"), addressLine3 = createTextRequestBody("Your Name"), place = createTextRequestBody("Fsafa"), pinCode = createPrimitiveRequestBody(642526), contactNumber = createTextRequestBody("Your Name"), email = createTextRequestBody("etet@gga.co"), isRegistered = createPrimitiveRequestBody(false), hasGst = createPrimitiveRequestBody(true), GSTNumber = createPrimitiveRequestBody(23423432), hasBankAccount = createPrimitiveRequestBody(false), averageTurnOver = createPrimitiveRequestBody(345346), hasInsurance = createPrimitiveRequestBody(false), staffSize = createPrimitiveRequestBody(546), ownerResponseId = createPrimitiveRequestBody(2), remarks = createTextRequestBody("Your Name"), runningFromDate = createTextRequestBody("Your Name"), storeSize = createPrimitiveRequestBody(324), storeTypeId = createPrimitiveRequestBody(2) )
4. Key Explanations
- Primitive Type Wrapping: Converting
Int/Booleanto strings and wrapping inRequestBodyensures Retrofit sends these values as valid form-data fields, avoiding unsupported raw serialization. - Safe Image Handling: Using
letcreates the image part only if the file exists, preventing null pointer exceptions. Passing the actualFileobject (not a string path) is critical for successful file upload. - MediaType Choice:
text/plainis the standard for simple text/primitive values in form-data;multipart/form-datarefers to the overall request structure, not individual fields. - Cleaner Code: Helper functions eliminate repetitive
RequestBody.createcalls and make the implementation easier to maintain.
5. Additional Checks
- Confirm your server endpoint expects exact, case-sensitive field names (e.g., "ImagePath", "Name") as specified in
@Part. - Verify the
Authorizationheader format (your "bearer " + token is standard, but double-check the token value is valid). - If image upload is optional, keep
imagePathnullable and passnullwhen no image is provided.
内容的提问来源于stack exchange,提问作者Manoj Perumarath
相关产品推荐
相关产品推荐

