我不太确定问题的原因是哪一方,但似乎
Gin
收到了请求,但不允许来自 android
应用程序的请求。我尝试 POST
的端点与具有类型字段的整体模型相关,并且该类型字段“告诉”Gin
哪些是必需的字段(对于我的系统的这一部分来说,我的工作流程有点复杂)。在 android
方面,我有一个该整体模型的对应模型,因为我将它用于应用程序中的某些内容。以前,我只需要从服务器获取与整体模型相关的数据。现在,我正在为其实现 POST
。服务器模型的 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
)
这是单体服务器模型的一个片段:
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"`
}
然后我像这样使用
POST
Thing
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,
)
//then the usual Retrofit boilerplate
使用这些代码,我只看到请求收到 201,但没有错误,即使我为进程中出现的每个错误对象返回一些内容。
这是 golang 代码顺便说一句:
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,
//other field association
}
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,
})
})
终于找到这个问题的答案了,我觉得和
gorm
有关。因此,在我实际的 Android 模型中,我添加了 created_at
,因为我需要它在 Android 端进行一些排序。因为它是 gorm
自动添加的字段,所以我认为在 POST
处理 Thing
时,我真的不需要为它提供值,我什至不需要将它传递给 Postman
。最初,我只是向它传递一个空字符串,但它不喜欢它。然后我想有
var thing_info models.ThingInfo
err := ctx.ShouldBind(&thing_info)
if err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
在我的代码中会给我返回错误,就像我迄今为止遇到的所有其他错误一样。但事实并非如此,不知何故,之前的错误没有返回给我。然后我插入了一个很好的ol'
fmt.Printf("thing_info bind err: %v\n", err)
在 if 语句中,最终得到一个错误(讽刺的是很高兴发现错误)。看起来,尽管
created_at
是一个 gorm
添加的字段,但它试图将我从 Android 应用程序传递的空字符串转换为日期和时间。经过一些测试,似乎传递一个看起来像 2023-08-07T4:46:00Z
的字符串是可以接受的,幸运的是,gorm
似乎忽略了该值并放置了记录的实际创建日期时间。