我想在Retrofit中调用POST方法(Django REST框架),为此,我从邮递员那里打电话给我,对我来说很好。
API接口:
public interface SOService {
@FormUrlEncoded
@POST("/api-auth/")
Call<Tokken> get_tokken(@Field("username") String username, @Field("password") String password);
}
APIUtility类为
public class ApiUtils {
public static final String BASE_URL = "http://10.0.2.2:8000/";
public static SOService getSOService() {
return RetrofitClient.getClient(BASE_URL).create(SOService.class);
}
}
RetrofitClient as:
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
最后,按以下方式调用该函数
private void signIn() {
boolean isValid = validate();
if (isValid) {
mService.get_tokken(user.getText().toString(), password.getText().toString()).enqueue(new Callback<Tokken>() {
@Override
public void onResponse(Call<Tokken> call, Response<Tokken> response) {
if (response.isSuccessful()) {
System.out.println("Te lo imprimo");
System.out.println(response.body().toString());
Toast.makeText(LoginActivity.this, "tokken recibido", Toast.LENGTH_SHORT).show();
} else {
int statusCode = response.code();
// handle request errors depending on status code
}
}
@Override
public void onFailure(Call<Tokken> call, Throwable t) {
Toast.makeText(LoginActivity.this, "Error al recibir tokken", Toast.LENGTH_SHORT).show();
t.printStackTrace();
Log.d("MainActivity", "error loading from API");
}
});
/*startActivity(new Intent(this, RolSelection.class));*/
}
}
最终结果总是一样,我在服务器上收到此消息:
[17 / Apr / 2018 01:12:33]“POST / api-auth / HTTP / 1.1”200 52
但在Android中我得到了这个:
I / System.out:Te lo imprimo Tokken {tokken = '空'}
知道为什么tokken为null?当我使用邮递员时,我得到一个结果。
使用Tokken类进行更新:
public class Tokken {
@SerializedName("tokken")
@Expose
private String tokken;
public String getTokken() {
return tokken;
}
public void setTokken(String tokken) {
this.tokken = tokken;
}
@Override
public String toString() {
return "Tokken{" +
"tokken='" + tokken + '\'' +
'}';
}
}
答案 0 :(得分:1)
更新:将Tokken类中的字段名称从@SerializedName("tokken")
更改为@SerializedName("token")
,如Postman附带的屏幕截图所示,以获得"token"
密钥,但不是"tokken"
。
也许它不是根本原因,但肯定是问题之一: 你没有正确配置改装客户端,你错过了添加http客户端:
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(clientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
答案 1 :(得分:1)
我认为你的问题是你的bean对象(Token
)有一个GSON注释要序列化为tokken
。
如果您将@SerializedName("tokken”)
更改为@SerializedName("token”)
,并假设请求没有其他问题,则应正确反序列化。
我不知道为什么你在一边叫它tokken
而在另一边叫token
,但如果可能的话我会尽量避免它,除非你打算加入单元测试以确保未来你不会忘记这一点。
另一种传递Body的方法(可能更容易,取决于......)是使用HashMap:
@POST("/api-auth/“)
Call<Tokken> get_tokken(@Body HashMap<String, Object> body);
然后你可以传递一个包含以下内容的地图:
[“username”, “YourUsername”],
[“password”, “YourPassword”]
但是没有额外的日志记录(或者介于两者之间的代理以查看实际发生的情况),调试非常困难。
请记住,您的问题的标题是“Retrofit POST方法返回错误400”。但是您的令牌为空是您的API返回400错误的副作用.400错误是“BAD REQUEST”,所以某些东西不是您的服务器期待。
nitpick :我将您的API方法重命名为getToken(…)
或fetchToken(…)
,使其更加适合Java / Kotlin / Android,并且更加不言自明。
答案 2 :(得分:1)
两次更改
将tokken
更改为token
@SerializedName("tokken")
@Expose
private String tokken;
到
@SerializedName("token")
@Expose
private String tokken;
删除SOService
中的额外“\”,它应该是
@FormUrlEncoded
@POST("api-auth/")