java.lang.IllegalArgumentException: URL "https:/my url/api/login/" 不包含“{username}”。 (参数#1)
java.lang.IllegalArgumentException: URL "https:/my url/api/login/" does not contain "{username}". (parameter #1)
我是 android 工作室的新手,我正在使用 java、改造和网络 api(django restframework)进行登录 activity。我收到此错误,java.lang.IllegalArgumentException:URL“https:// my url /api/login/”不包含“{username}”。 (参数#1)
对于方法 UserService.login ,为什么会出现此错误?即使我的网站 api 正常工作?
这是我的post数据
这是我的LoginActivity.java
public class LoginActivity extends AppCompatActivity {
EditText edtUsername;
EditText edtPassword;
Button btnLogin;
UserService userService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
edtUsername = (EditText) findViewById(R.id.edtUsername);
edtPassword = (EditText) findViewById(R.id.edtPassword);
btnLogin = (Button) findViewById(R.id.btnLogin);
userService = ApiUtils.getUserService();
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = edtUsername.getText().toString();
String password = edtPassword.getText().toString();
//validate form
if(validateLogin(username, password)){
//do login
doLogin(username, password);
}
}
});
}
private boolean validateLogin(String username, String password){
if(username == null || username.trim().length() == 0){
Toast.makeText(this, "Username is required", Toast.LENGTH_SHORT).show();
return false;
}
if(password == null || password.trim().length() == 0){
Toast.makeText(this, "Password is required", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private void doLogin(final String username,final String password){
Call call = userService.login(username,password);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if(response.isSuccessful()){
ResObj resObj = (ResObj) response.body();
if(resObj.getMessage().equals("true")){
//login start main activity
Intent intent = new Intent(LoginActivity.this, DestinationListActivity.class);
intent.putExtra("username", username);
startActivity(intent);
} else {
Toast.makeText(LoginActivity.this, "The username or password is incorrect", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(LoginActivity.this, "Error! Please try again!", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
我的用户服务
public interface UserService {
@POST("https:// my url /api/login/")
Call login(@Path("username") String username, @Path("password") String password);
}
这是我的 RetrofitClient
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String url){
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
我的资源对象
public class ResObj {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
我的 ApiUtils
public class ApiUtils {
public static final String BASE_URL = "https:// my url /";
public static UserService getUserService(){
return RetrofitClient.getClient(BASE_URL).create(UserService.class);
}
}
这是我收到的完整错误
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.smartherd.globofly, PID: 27242
java.lang.IllegalArgumentException: URL "https:// my url /api/login/" does not contain "{username}". (parameter #1)
for method UserService.login
at retrofit2.Utils.methodError(Utils.java:52)
at retrofit2.Utils.methodError(Utils.java:42)
at retrofit2.Utils.parameterError(Utils.java:61)
at retrofit2.RequestFactory$Builder.validatePathName(RequestFactory.java:732)
at retrofit2.RequestFactory$Builder.parseParameterAnnotation(RequestFactory.java:375)
at retrofit2.RequestFactory$Builder.parseParameter(RequestFactory.java:295)
at retrofit2.RequestFactory$Builder.build(RequestFactory.java:182)
at retrofit2.RequestFactory.parseAnnotations(RequestFactory.java:65)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:25)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:168)
at retrofit2.Retrofit.invoke(Retrofit.java:147)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy3.login(Unknown Source)
at com.smartherd.globofly.activities.LoginActivity.doLogin(LoginActivity.java:64)
at com.smartherd.globofly.activities.LoginActivity.access0(LoginActivity.java:20)
at com.smartherd.globofly.activities.LoginActivity.onClick(LoginActivity.java:44)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access00(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
I/Process: Sending signal. PID: 27242 SIG: 9
更新
对于 @POST
类型的请求,您还可以使用 @Field
来传递表单编码请求的各个字段。
@FormUrlEncoded
@POST("https://www.url.com/api/login/")
Call login(@Field("username") String username, @Field("password") String password);
@Field
的文档和示例。
要处理响应:
定义一个简单的classAuthenticationResponse
:
public class AuthenticationResponse {
public String token;
}
并将其用作 login
调用的通用类型参数:
@FormUrlEncoded
@POST("https://www.url.com/api/login/")
Call<AuthenticationResponse> login(@Field("username") String username, @Field("password") String password);
使用 AuthenticationResponse
需要更新您的 LoginActivity
方法 doLogin
:
private void doLogin(final String username, final String password) {
Call<AuthenticationResponse> call = userService.login(username, password);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
AuthenticationResponse authResponse = (AuthenticationResponse) response.body();
if (!TextUtils.isEmpty(authResponse.token)) {
//login start main activity
Intent intent = new Intent(LoginActivity.this, DestinationListActivity.class);
intent.putExtra("username", username);
startActivity(intent);
} else {
Toast.makeText(LoginActivity.this, "The username or password is incorrect", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(LoginActivity.this, "Error! Please try again!", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
对于 @POST
类型的请求,如果您需要将参数作为请求 body 的一部分,那么您必须使用 @Body
注释对这些参数进行注释。但是您只能使用一个 @Body
注释,因为使用该注释声明的参数将定义请求的整个主体。
@POST("https://www.url.com/api/login/")
Call login(@Body Credentials credentials);
其中 Credentials
是一个 POJO class:
class Credentials {
public String username;
public String password;
}
@Body
的文档。
为什么会发生错误?
当您使用 @Path("name")
注释时,您必须在 URL.
中为该路径参数提供一个占位符
而不是:
@POST("https://www.url.com/api/login/")
Call login(@Path("username") String username, @Path("password") String password);
您的 POST 调用声明应该如下所示,这样 Retrofit 就会知道将这些路径参数放在哪里:
@POST("https://www.url.com/api/login/{username}/{password}")
Call login(@Path("username") String username, @Path("password") String password);
@Path
的文档和示例。
您的登录 http 端点是否期望您将登录数据(用户名、密码)作为正文中的 urlencoded 参数发送?
然后尝试像这样修改您的 UserService 接口:
public class ResObj {
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
public interface UserService {
@FormUrlEncoded
@POST("https:// my url /api/login/")
Call<ResObj> login(@Field("username") String username, @Field("password") String password);
}
我是 android 工作室的新手,我正在使用 java、改造和网络 api(django restframework)进行登录 activity。我收到此错误,java.lang.IllegalArgumentException:URL“https:// my url /api/login/”不包含“{username}”。 (参数#1) 对于方法 UserService.login ,为什么会出现此错误?即使我的网站 api 正常工作?
这是我的post数据
这是我的LoginActivity.java
public class LoginActivity extends AppCompatActivity {
EditText edtUsername;
EditText edtPassword;
Button btnLogin;
UserService userService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
edtUsername = (EditText) findViewById(R.id.edtUsername);
edtPassword = (EditText) findViewById(R.id.edtPassword);
btnLogin = (Button) findViewById(R.id.btnLogin);
userService = ApiUtils.getUserService();
btnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String username = edtUsername.getText().toString();
String password = edtPassword.getText().toString();
//validate form
if(validateLogin(username, password)){
//do login
doLogin(username, password);
}
}
});
}
private boolean validateLogin(String username, String password){
if(username == null || username.trim().length() == 0){
Toast.makeText(this, "Username is required", Toast.LENGTH_SHORT).show();
return false;
}
if(password == null || password.trim().length() == 0){
Toast.makeText(this, "Password is required", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private void doLogin(final String username,final String password){
Call call = userService.login(username,password);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if(response.isSuccessful()){
ResObj resObj = (ResObj) response.body();
if(resObj.getMessage().equals("true")){
//login start main activity
Intent intent = new Intent(LoginActivity.this, DestinationListActivity.class);
intent.putExtra("username", username);
startActivity(intent);
} else {
Toast.makeText(LoginActivity.this, "The username or password is incorrect", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(LoginActivity.this, "Error! Please try again!", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
我的用户服务
public interface UserService {
@POST("https:// my url /api/login/")
Call login(@Path("username") String username, @Path("password") String password);
}
这是我的 RetrofitClient
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String url){
if(retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
我的资源对象
public class ResObj {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
我的 ApiUtils
public class ApiUtils {
public static final String BASE_URL = "https:// my url /";
public static UserService getUserService(){
return RetrofitClient.getClient(BASE_URL).create(UserService.class);
}
}
这是我收到的完整错误
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.smartherd.globofly, PID: 27242
java.lang.IllegalArgumentException: URL "https:// my url /api/login/" does not contain "{username}". (parameter #1)
for method UserService.login
at retrofit2.Utils.methodError(Utils.java:52)
at retrofit2.Utils.methodError(Utils.java:42)
at retrofit2.Utils.parameterError(Utils.java:61)
at retrofit2.RequestFactory$Builder.validatePathName(RequestFactory.java:732)
at retrofit2.RequestFactory$Builder.parseParameterAnnotation(RequestFactory.java:375)
at retrofit2.RequestFactory$Builder.parseParameter(RequestFactory.java:295)
at retrofit2.RequestFactory$Builder.build(RequestFactory.java:182)
at retrofit2.RequestFactory.parseAnnotations(RequestFactory.java:65)
at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:25)
at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:168)
at retrofit2.Retrofit.invoke(Retrofit.java:147)
at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
at $Proxy3.login(Unknown Source)
at com.smartherd.globofly.activities.LoginActivity.doLogin(LoginActivity.java:64)
at com.smartherd.globofly.activities.LoginActivity.access0(LoginActivity.java:20)
at com.smartherd.globofly.activities.LoginActivity.onClick(LoginActivity.java:44)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access00(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
I/Process: Sending signal. PID: 27242 SIG: 9
更新
对于 @POST
类型的请求,您还可以使用 @Field
来传递表单编码请求的各个字段。
@FormUrlEncoded
@POST("https://www.url.com/api/login/")
Call login(@Field("username") String username, @Field("password") String password);
@Field
的文档和示例。
要处理响应:
定义一个简单的classAuthenticationResponse
:
public class AuthenticationResponse {
public String token;
}
并将其用作 login
调用的通用类型参数:
@FormUrlEncoded
@POST("https://www.url.com/api/login/")
Call<AuthenticationResponse> login(@Field("username") String username, @Field("password") String password);
使用 AuthenticationResponse
需要更新您的 LoginActivity
方法 doLogin
:
private void doLogin(final String username, final String password) {
Call<AuthenticationResponse> call = userService.login(username, password);
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
if (response.isSuccessful()) {
AuthenticationResponse authResponse = (AuthenticationResponse) response.body();
if (!TextUtils.isEmpty(authResponse.token)) {
//login start main activity
Intent intent = new Intent(LoginActivity.this, DestinationListActivity.class);
intent.putExtra("username", username);
startActivity(intent);
} else {
Toast.makeText(LoginActivity.this, "The username or password is incorrect", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(LoginActivity.this, "Error! Please try again!", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(LoginActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
对于 @POST
类型的请求,如果您需要将参数作为请求 body 的一部分,那么您必须使用 @Body
注释对这些参数进行注释。但是您只能使用一个 @Body
注释,因为使用该注释声明的参数将定义请求的整个主体。
@POST("https://www.url.com/api/login/")
Call login(@Body Credentials credentials);
其中 Credentials
是一个 POJO class:
class Credentials {
public String username;
public String password;
}
@Body
的文档。
为什么会发生错误?
当您使用 @Path("name")
注释时,您必须在 URL.
而不是:
@POST("https://www.url.com/api/login/")
Call login(@Path("username") String username, @Path("password") String password);
您的 POST 调用声明应该如下所示,这样 Retrofit 就会知道将这些路径参数放在哪里:
@POST("https://www.url.com/api/login/{username}/{password}")
Call login(@Path("username") String username, @Path("password") String password);
@Path
的文档和示例。
您的登录 http 端点是否期望您将登录数据(用户名、密码)作为正文中的 urlencoded 参数发送? 然后尝试像这样修改您的 UserService 接口:
public class ResObj {
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
public interface UserService {
@FormUrlEncoded
@POST("https:// my url /api/login/")
Call<ResObj> login(@Field("username") String username, @Field("password") String password);
}