Android端Retrofit向Gin服务POST请求失败,Postman请求正常
问题描述
不确定问题出在哪一端,但Gin已接收到Android应用的请求却未正常处理。我在实现一个POST接口,接口关联的单体模型带有type字段,用来告知Gin哪些是必填字段(这部分系统流程较复杂)。Android端有对应此模型的本地实体类,之前仅实现了从服务器拉取数据的功能,现在要完成POST提交逻辑。
请求返回201状态码,但未出现预期的错误信息,尽管流程中每个错误分支都做了返回处理。
Android端模型代码
@Entity(tableName = "thing", indices = [Index(value = ["id"], unique = true)]) data class Thing( @PrimaryKey(autoGenerate = false) @ColumnInfo(name = "id") var id: String, @SerializedName("CreatedAt") @ColumnInfo(name = "created_at") var created_at: String, @ColumnInfo(name = "name") var name: String, @ColumnInfo(name = "type_id") var type_id: String, @ColumnInfo("type") var type: ThingType? = null, @ColumnInfo( name = "some_field_1", defaultValue = "0" ) var some_field_1: Float = 0.0f, @ColumnInfo( name = "some_field_2", defaultValue = "0" ) var some_field_2: Float = 0.0f, @ColumnInfo( name = "some_field_3", defaultValue = "0" ) var some_field_3: Float = 0.0f, @ColumnInfo( name = "some_field_4", defaultValue = "0" ) var some_field_4: Float = 0.0f, @ColumnInfo( name = "some_field_5", defaultValue = "0" ) var some_field_5: Float = 0.0f, @ColumnInfo( name = "parent_id", defaultValue = "0" ) var parent_id: String )
服务端Go模型代码片段
type Thing struct { gorm.Model ID string `gorm:"primarykey; size:40;" json:"id"` Name string `json:"name"` TypeId string `gorm:"size:40; index; not null" json:"type_id"` Type Type `gorm:"foreignKey:TypeId; constraint:OnUpdate:CASCADE,OnDelete:CASCADE" json:"type"` SomeField1 float32 `json:"some_field_1"` SomeField2 float32 `json:"some_field_2"` SomeField3 float32 `json:"some_field_3"` SomeField4 float32 `json:"some_field_4"` SomeField5 float32 `json:"some_field_5"` ParentId float32 `json:"parent_id"` }
Android Retrofit请求代码
@POST("/thing_info") suspend fun postThingInfo( @HeaderMap headers: Map<String, String>, @Body data: Thing ): Response<Thing> val thing = Thing( "", "", name = binding.txtName.text.toString(), type_id = typeId, some_field_1 = binding.txtSomeField1.text.toString() .toFloat(), some_field_2 = binding.txtSomeField2.text.toString() .toFloat(), some_field_3 = binding.txtSomeField3.text.toString() .toFloat(), parent_id = parentId, ) // Retrofit常规初始化代码省略
Gin端接口处理代码
ginGine.POST("/thing_info", func(ctx *gin.Context) { errMsg := clnHelpers.ValidateAccessToken(ctx.GetHeader("access_token")) if errMsg != "" { ctx.JSON(http.StatusBadRequest, gin.H{ "error": errMsg, }) return } var thing_info models.Thing err := ctx.ShouldBind(&thing_info) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } data := &pb.ThingInfo{ Name: thing_info.Name, TypeId: thing_info.TypeId, // 其他字段映射省略 } res, err := srvClient.service.CreateThingInfo(ctx, &pb.CreateThingInfoRequest{ ThingInfo: data, }) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{ "error": err.Error(), }) return } ctx.JSON(http.StatusCreated, gin.H{ "thing_info": res.ThingInfo, }) })
排查方向
- 字段类型不匹配:服务端
ParentId是float32类型,但Android端parent_id是String类型,可能导致JSON反序列化异常,或数据转换后不符合下游服务要求。 type字段缺失:Android端创建Thing对象时未设置type字段(默认传null),而服务端依赖该字段判断必填项,但Gin的ShouldBind默认不会校验字段非空,需检查是否添加了binding:"required"这类校验标签。- 日志缺失:在Gin各个分支添加日志,打印
thing_info绑定结果、下游gRPC请求参数,确认数据是否正确传递。 - 下游服务无校验:如果
CreateThingInfo接口本身未校验必填字段,即使数据缺失也会返回成功,导致Gin返回201,需检查下游服务逻辑。 - Android序列化问题:确认Retrofit使用的JSON序列化器(如Gson)是否正确处理
type字段的null值,是否将其序列化为null或直接忽略,导致服务端接收不到该字段。
内容的提问来源于stack exchange,提问作者rminaj
相关产品推荐
相关产品推荐

