【问题标题】:How can I send a post request with Retrofit?如何使用 Retrofit 发送发布请求?
【发布时间】:2019-04-04 14:07:23
【问题描述】:

我正在尝试使用 Retrofit 发送发布请求,但服务器响应错误 400:错误请求。

基本网址:http://taskdemoserver.pythonanywhere.com

这是服务器文档的截图。

这是改造界面。

package com.e.databaseapp

import retrofit2.Call
import retrofit2.http.*

interface Service {
    @Headers("user: joan","Content-Type: application/json")
    @GET( "task" )
    fun getListTask() : Call<TaskListContainer>

    @Headers("user: joan","Content-Type: application/json")
    @POST("task")
    fun saveTask (@Body task: Task) : Call<Task>

    @Headers("user: joan")
    @DELETE("task")
    fun deleteTask (task: String) : Call<Void>
}

我在我的存储库中创建了一个 Retrofit 实例。

lass TaskRepository(val taskDao: TaskDao) {
    val gson : Gson = GsonBuilder()
        .setLenient()
        .create()

    val loggingInterceptor : HttpLoggingInterceptor = HttpLoggingInterceptor()
        .setLevel(HttpLoggingInterceptor.Level.BODY)

    val httpClient : OkHttpClient = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)
        .build()

    val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl("http://taskdemoserver.pythonanywhere.com/")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(httpClient)
        .build()

    val service: Service = retrofit.create(Service::class.java)

...

}

这是我尝试发布任务时遇到的错误。

【问题讨论】:

  • 添加您的基本网址或邮递员图片
  • 请添加代码,您将在其中创建改造服务的实例以及代码,您将在其中执行实际调用
  • 您能否使用最新版本的代码更新您的问题,并详细说明您的服务器端点以及您现在遇到的错误是什么?
  • @dglozano 这是我的代码的最新版本
  • 你没有按照我在回答中所说的去做。您不应该发送应用程序/json,您的服务器期望以 FormUrlEncoded 形式获取它。删除 @Body 注释并在顶部包含注释 @FormUrlEncoded。检查我的更新答案

标签: android kotlin retrofit


【解决方案1】:

基本 URL 应始终以 / 结尾

中更改.baseUrl("http://taskdemoserver.pythonanywhere.com")
val retrofit: Retrofit = Retrofit.Builder()
        .baseUrl("http://taskdemoserver.pythonanywhere.com")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(httpClient)
        .build()

.baseUrl("http://taskdemoserver.pythonanywhere.com/")

【讨论】:

  • 斜杠属于改造中的基本url。
  • @DanielSpiess 在他的代码中我看到了这个.baseUrl("http://taskdemoserver.pythonanywhere.com")
  • 我不认为在今天的改造版本中,斜线在基本 URL 和界面中都是强制性的..
  • 是的,您在服务中添加了斜线。但我属于基本网址。对不起,但你的解决方案是错误的。 square.github.io/retrofit/2.x/retrofit/retrofit2/…
  • @DanielSpiess 是的,但是基本 url 应该在 / 中。我更新了答案
【解决方案2】:

您可能有以下问题:

1) 服务器无法定义响应的内容。 尝试添加内容类型的标题:@Headers("Content-Type: application/json")

2) 您的基本网址末尾缺少 / 斜线。

【讨论】:

    【解决方案3】:

    尽管我不能 100% 确定这是否是您的问题,但由于您上传的服务器文档不完整,我很确定问题在于服务器要求您发送任务的数据要使用 mime 类型 application/x-www-form-urlencoded 创建,这就是为什么它在您与服务器文档一起上传的图片中的 Create Task 端点右侧显示 formdata

    但是,您使用的是@Body tasks: TaskListContainer,而是将新任务的信息作为 JSON 数据 application/json 发送。 (@Body annotation)

    这就是你正在做的事情

    我使用application/json 作为您请求的内容类型,使用Postman 测试了您的端点。这就是 Retrofit 现在正在做的事情,因为您在 Retrofit 服务中使用了 @Body 注释。

    你应该这样做

    现在,如果我使用 Postman 发送 POST 请求,但使用 form-data 类型,并使用带有键 task 的字段和表示要创建的任务名称的字符串值,我会得到一个成功的响应。

    要告诉 Retrofit 像这样发送 POST 请求,你必须像这样定义你的 saveTask 方法:

        interface Service {
        ...
    
        @Headers("user: joan")
        @FormUrlEncoded
        @POST("task")
        fun saveTask (@Field("task") taskname: String) : Call<Task>
    
        ...
    }
    

    您可以在the official documentation 中查看有关@FormUrlEncoded 注解的更多信息。

    另外,正如@YuriPopiv 所说,您的baseUrl 中缺少最后一个斜线。尝试像这样设置它.baseUrl("http://taskdemoserver.pythonanywhere.com/") 或以前导 / 开头定义您的端点。

    来自the docs

    基本 URL 应始终以 / 结尾。 尾随 / 确保作为相对路径的端点值将正确地附加到具有路径组件的基础上。

    【讨论】:

    • 首先感谢您的回答。现在服务器响应 401 错误:未授权
    • 嗯,这是一个全新的错误。这是因为服务器希望您在能够向该端点发出请求之前通过身份验证。每台服务器都有自己的认证方式,不知道你的服务器用的是什么认证方式。它可以是简单的基本身份验证,也可以使用更高级的机制,如 JWT 令牌。如果您将服务器的详细信息发送给我,我可能会为您提供帮助。你可以开始看看futurestud.io/tutorials/…
    • 还没有...一旦错误 401 得到修复,它再次给我错误 400
    猜你喜欢
    • 2015-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 2014-10-08
    • 2019-12-08
    • 2020-04-06
    相关资源
    最近更新 更多