在 Retrofit 2 和 OkHttp3 中使用 @PUT

Using @PUT with Retrofit 2 and OkHttp3

目前,我正在使用 Android 与 Retrofit 2.0.0-beta4 和 OkHttp3。我正在做一个定义为这样的@PUT 请求:

@Headers({
        Constants.CONTENT_TYPE_HEADER + ": " + Constants.JSON_HEADER_VAL,
        Constants.ACCEPT_HEADER + ": " + Constants.JSON_HEADER_VAL
})
@PUT(Constants.PUT_SKILL_LEVEL)
Call<EmployeeSkill> updateEmpSkillLevel(@Header(Constants.SESSION_COOKIE_NAME) String cookieValue, @Body EmployeeSkillRequest employeeSkillUpdate);

端点在此处:http://apps:8080/employeeSkillsService/employeeSkill。这是 PUT 请求的日志输出:

D/OkHttp﹕ --> PUT http://apps:8080/employeeSkillsService/employeeSkill http/1.1
D/OkHttp﹕ Content-Type: application/json;charset=UTF-8
D/OkHttp﹕ Content-Length: 99
D/OkHttp﹕ Accept: application/json
D/OkHttp﹕ JSESSIONID: D147377AB60AFE499D2A1AAF7C93F7A3
D/OkHttp﹕ {"employee":{"id":63},"skill":{"isPrimary":false,"isSecondary":false,"id":3},"skillLevel":{"id":5}}
D/OkHttp﹕ --> END PUT (99-byte body)
<-- 404 Not Found http://apps:8080/employeeSkillsService/app.html (23ms)
D/OkHttp﹕ Server: Apache-Coyote/1.1
D/OkHttp﹕ X-Content-Type-Options: nosniff`D/OkHttp﹕ X-XSS-Protection: 1; mode=block`
D/OkHttp﹕ X-XSS-Protection: 1; mode=block
D/OkHttp﹕ Cache-Control: no-cache, no-store, max-age=0, must-revalidate
D/OkHttp﹕ Pragma: no-cache
D/OkHttp﹕ Expires: 0
D/OkHttp﹕ X-Frame-Options: DENY
D/OkHttp﹕ Content-Type: text/html;charset=utf-8
D/OkHttp﹕ Content-Language: en
D/OkHttp﹕ Content-Length: 1029
D/OkHttp﹕ Date: Mon, 07 Mar 2016 15:39:35 GMT
D/OkHttp﹕ OkHttp-Sent-Millis: 1457365206407
D/OkHttp﹕ OkHttp-Received-Millis: 1457365206412
D/OkHttp﹕ <html><head><title>Apache Tomcat/7.0.52 (Ubuntu) - Error report</title><style><!--H1 
{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 
{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 
{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B{font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}--></style> </head><body><h1>HTTP Status 404 - /employeeSkillsService/app.html</h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u>/employeeSkillsService/app.html</u></p><p><b>description</b> <u>The requested resource is not available.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.52 (Ubuntu)</h3></body></html>
D/OkHttp﹕ <-- END HTTP (1029-byte body)

我已经在 Chrome 上的 Postman 中验证了具有这些 headers 和负载的端点可以多次工作。然而,当我使用 Retrofit 时,尽管端点在 Postman 中工作,但我仍然收到 404 错误。这是代码调用:

Call<EmployeeSkill> updateEmployeeSkillCall = RetrofitApiRestClient.getApiClient().updateEmpSkillLevel(cookieValue, employeeSkillUpdate);

updateEmployeeSkillCall.enqueue(new Callback<EmployeeSkill>() {

    @Override
    public void onResponse(Call<EmployeeSkill> call, Response<EmployeeSkill> response) {
        // called when response HTTP status is "200 OK"
        if (response.isSuccess()) {
            holder.spnSkillLevel.setTag(pos);
            Toast.makeText(mContext, holder.tvSkillName.getText() + mContext.getString(R.string.skill_updated_success_text)
                + holder.spnSkillLevel.getSelectedItem().toString(), Toast.LENGTH_LONG).show();

            List<EmployeeSkill> updateEmployeeSkillsRow = EmployeeSkill.find(EmployeeSkill.class, "employee = ? and skill = ?",
                response.body().getEmployee().getId().toString(), response.body().getSkill().getId().toString());

            EmployeeSkill updatedSkill = updateEmployeeSkillsRow.get(0);
            updatedSkill.setSkillLevel(response.body().getSkillLevel());
            updatedSkill.setTimeUpdated(response.body().getSkillLevel().getTimeUpdated());
            updatedSkill.save();
        }
    }

    @Override
    public void onFailure(Call<EmployeeSkill> call, Throwable throwable) {
        Toast.makeText(mContext, holder.tvSkillName.getText() + mContext.getString(R.string.skill_update_failed_text), Toast.LENGTH_LONG).show();
    }
});

我曾尝试将 @Body 参数更改为 JSON 字符串,但我收到一条错误消息,指出 JSON 必须以数组或 object.在这件事上的任何帮助都是有用的。没有这个功能,如果我找不到解决方案,我将被迫放弃 Retrofit,而且我真的不期待这样做。

使用 Fiddler2 解决了我自己的问题。 cookie 名称和值不正确。与 Retrofit 和其他人发送邮件的方式相比,Postman 在发送邮件的方式上可能更加宽容。不过,从中学到了一些东西。感谢所有提供帮助的人。