You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Retrofit+Kotlin调用DialogFlow Post请求出现400错误求助

排查DialogFlow Retrofit请求400错误的问题

我帮你对比了Python的可用实现和你的Kotlin代码,找到了几个核心问题导致400 Bad Request错误,下面逐个说明并给出修复方案:

1. 请求体字段名不匹配(最关键问题)

你的Python代码里请求体的键是sessionId,但Kotlin的MsgBody类里定义的是sesId:

data class MsgBody(val lang: String, val query: String, val sesId: String)

Gson默认会把Kotlin字段名直接作为JSON键,所以发送的请求体里会是"sesId": "me",而DialogFlow的API明确期望"sessionId": "me",这直接导致请求格式不符合要求,触发400错误。

修复方案:
要么直接修改字段名,要么用@SerializedName注解指定JSON键:

// 方案1:直接改名(推荐)
data class MsgBody(val lang: String, val query: String, val sessionId: String)

// 方案2:保留原变量名,用注解映射JSON键
import com.google.gson.annotations.SerializedName
data class MsgBody(
    val lang: String,
    val query: String,
    @SerializedName("sessionId") val sesId: String
)

2. 响应模型字段名错误

DialogFlow的响应结构顶层字段是result,但你的Model.Response类里定义的是resp:

data class Response(val resp: Result)

这会导致Gson无法正确解析响应数据,即使请求成功也会抛出解析异常。

修复方案:
同样修改字段名或用注解映射:

// 方案1:直接改名
data class Response(val result: Result)

// 方案2:用注解保留原变量名
data class Response(@SerializedName("result") val resp: Result)

3. Header的API KEY写法错误

你在@Headers里写了"Authorization: Bearer {MY API KEY}",这种写法是错误的——Retrofit的静态@Headers不支持占位符,这里会直接把{MY API KEY}作为字符串发送,导致鉴权失败。

修复方案:
如果API KEY是固定的,直接替换成实际的KEY字符串;如果需要动态传入,改用@Header注解:

// 静态固定KEY的写法
@Headers( "Authorization: Bearer 你的实际API KEY", "Content-Type: application/json" )
@POST("query")
fun getAiMessage(@Body msg: Message.MsgBody, @Query("v") v: String): Observable<Model.Response>

// 动态传入KEY的写法(更灵活,适合KEY需要动态配置的场景)
@POST("query")
fun getAiMessage(
    @Header("Authorization") auth: String,
    @Body msg: Message.MsgBody,
    @Query("v") v: String
): Observable<Model.Response>

// 调用时传入示例:
dialogFlowService.getAiMessage("Bearer 你的实际API KEY", Message.MsgBody("en",msg,"me"),"20170712")

4. 其他小细节修正

  • 你的代码里getAiMessage方法返回的是Observable<Model1.Response>,这里是笔误,应该改成Observable<Model.Response>。
  • 建议添加OkHttp日志拦截器,方便查看实际发送的请求体和响应内容,快速定位问题:
// 先添加依赖:implementation 'com.squareup.okhttp3:logging-interceptor:4.10.0'
val logging = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }
val client = OkHttpClient.Builder().addInterceptor(logging).build()

// 在Retrofit构建时添加客户端
val retrofit = Retrofit.Builder()
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .addConverterFactory(GsonConverterFactory.create())
    .baseUrl("https://api.dialogflow.com/v1/")
    .client(client)
    .build()

修正后的完整代码示例

Message.kt

object Message {
    data class MsgBody(
        val lang: String,
        val query: String,
        val sessionId: String // 修正字段名
    )
}

Model.kt

object Model {
    data class Response(val result: Result) // 修正字段名
    data class Result(val fulfillment: Fulfillment)
    data class Fulfillment(val speech: String)
}

DialogFlowService.kt

import io.reactivex.Observable
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.Query

interface DialogFlowService {
    @POST("query")
    fun getAiMessage(
        @Header("Authorization") authToken: String,
        @Body msg: Message.MsgBody,
        @Query("v") apiVersion: String
    ): Observable<Model.Response>

    companion object {
        fun create(): DialogFlowService {
            val logging = HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            }
            val okHttpClient = OkHttpClient.Builder()
                .addInterceptor(logging)
                .build()

            val retrofit = Retrofit.Builder()
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://api.dialogflow.com/v1/")
                .client(okHttpClient)
                .build()
            return retrofit.create(DialogFlowService::class.java)
        }
    }
}

MainActivity调用代码

private fun sendMessage(msg: String){
    val authToken = "Bearer 你的实际API KEY"
    disposable = dialogFlowService.getAiMessage(authToken, Message.MsgBody("en",msg,"me"),"20170712")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(
            { result -> 
                textView.text = "DialogFlow says: ${result.result.fulfillment.speech}" // 修正响应字段路径
            }, 
            { error -> 
                Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show() 
            }
        )
}

按照以上修改后,应该就能正确发送请求并获取DialogFlow的响应了。

内容的提问来源于stack exchange,提问作者mradey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 15:14:09