【问题标题】:Android/Kotlin retrofit2.adapter.rxjava2.HttpException: HTTP 415 Unsupported Media TypeAndroid/Kotlin retrofit2.adapter.rxjava2.HttpException: HTTP 415 Unsupported Media Type
【发布时间】:2019-11-08 12:40:36
【问题描述】:

我刚从Retrofit 开始,当我试图制作一个简单的POST request 时出现此错误

retrofit2.adapter.rxjava2.HttpException:HTTP 415 不受支持的媒体 类型

我完全不知道错在哪里。
我已经按照这个tutorial 来实现Retrofit 和RxJava。

我的RetrofitClient 实现了我的OkHttpClient:

object RetrofitClient {

    private const val CONNECTION_TIMEOUT: Long = 60
    private val BASE_URL = "https://pictalio-dev.azurewebsites.net/api/"

    private var retrofit: Retrofit? = null


    fun getClient(token: String): Retrofit {
        if (retrofit == null) {
            retrofit = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(getOkHttpClient(token))
                    .build()
        }
        return retrofit!!
    }

    private fun getOkHttpClient(token: String): OkHttpClient {
        val okClientBuilder = OkHttpClient.Builder()
        val httpLoggingInterceptor = HttpLoggingInterceptor()
        okClientBuilder.addInterceptor { chain ->
            val original = chain.request()

            val requestBuilder = original.newBuilder()
                    .header("Authorization", token)

            val request = requestBuilder.build()
            chain.proceed(request)
        }
        httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BASIC
        okClientBuilder.addInterceptor(httpLoggingInterceptor)
        okClientBuilder.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
        okClientBuilder.readTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
        okClientBuilder.writeTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
        return okClientBuilder.build()
    }
}

还有我的ApiService:

interface ApiService {
    @FormUrlEncoded
    @POST("account/login")
    fun getUserLogin(
            @Field("email") email: String,
            @Field("password") password: String
    ): Single<User>
}

这是我如何调用和处理我的请求返回的:

class SignInActivity : AppCompatActivity(), View.OnClickListener, RequestSignIn.sendDataResponse, RequestGetUser.sendDataResponse {

    private var user: User? = null
    private var pDialog: SweetAlertDialog? = null
    lateinit var emailEditText: EditText
    lateinit var passwordEditText: EditText
    var persistentUser: PersistentUser? = null
    //Initialization of disposable
    private val disposable = CompositeDisposable()

    private lateinit var apiService: ApiService

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.signin_activity)

        emailEditText = findViewById(R.id.email)
        passwordEditText = findViewById(R.id.password)
        //Initialization of apiService
        apiService = RetrofitClient.getClient("").create(ApiService::class.java)
    }

    override fun onClick(v: View) {
        val email: EditText
        val password: EditText

        email = findViewById(R.id.email)
        password = findViewById(R.id.password)
            R.id.login -> {
                if (Tools.isValidEmail(email.text.toString())) {
          disposable.add(apiService.getUserLogin(email.text.toString(), password.text.toString())
                            .subscribeOn(Schedulers.io())
                            .observeOn(AndroidSchedulers.mainThread())
                            .subscribe({ user ->
                                pDialog!!.dismissWithAnimation()
                                Log.e("USER", "token: " + user.token)

                            }, Throwable::printStackTrace)
                    )
                } else {
                    Toast.makeText(this@SignInActivity, getString(R.string.enter_valid_email), Toast.LENGTH_SHORT).show()
                    //emailnotvalid
                }
            }
        }

    }

    override fun onDestroy() {
        super.onDestroy()
        disposable.dispose()
    }
}

我们将不胜感激。

编辑:
我已删除 @FormUrlEncoded 并添加 .header("Content-Type", "application/json")
我现在将JSONObject 发送为Body,如下所示:

disposable.add(apiService.getUserLogin(JSONObject(map)))  

但我的服务器上有一个400 BAD REQUEST。
我什至将ScalarsConverter 添加到我的RetrofitClient。

.addConverterFactory(ScalarsConverterFactory.create())

所以我尝试使用RequestBody 如下

fun getUserLogin(@Body requestBody: String): Single<User>
disposable.add(apiService.getUserLogin(RequestBody.create(MediaType.parse("application/json"), JSONObject(map).toString())) . 

而且效果也很好!我怎样才能简单地发送一个JSONObject 而不是每次都创建一个RequestBody?

【问题讨论】:

    标签: android kotlin retrofit2 rx-java2 okhttp3


    【解决方案1】:

    状态码4xx表示客户端发送的请求有错误;在这种特定情况下,415 表示服务器不支持您请求的 Content-Type。

    检查您在代码中提供的 URL,服务器需要 application/json-patch+json MIME 类型,但您提供的是 application/x-www-form-urlencoded(这就是 @FormUrlEncoded 注释的用途)。

    要解决此问题,您应该更改 getUserLogin 方法以使用适当的 Content-Type(请参阅 this answer)并发送适当的 JSON 有效负载(请参阅 this answer,它还告诉您如何设置自定义标头)。

    【讨论】:

    • 感谢您的回答,这是有效的,但如果您能看到我的编辑,我仍然有问题,请 :)
    • 检查一下为什么第一个解决方案会给您一个 400 Bad Request 会很有趣,但这需要调试或至少添加一个拦截器来记录您的请求。我的猜测是,您可能在 getUserLogin 方法中的参数之前忘记了 @Body 注释(在前面的示例中您有 @Field),因为这将告诉 Retrofit 使用该参数作为您的请求正文称呼。不过,我不会为此赌钱:-)
    • 没有。我已经在我的论点之前放了@Body :) 检查新的编辑
    • 我已经调试过了,我的身体有Content-Type: text/plain; charset=utf-8。如何将其更改为 application/json ?我已经为我的header 设置了,但它不会影响Body。
    • 好的,我会保留的,哈哈,谢谢你的解释并解封了我!
    猜你喜欢
    • 1970-01-01
    • 2021-07-16
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-16
    • 2018-06-10
    相关资源
    最近更新 更多