英文:
Volley POST with URL ENCODED parameters not being passed
问题
我需要进行一个带有url编码参数的HTTPS POST 请求,如下所示:
并且返回一个JSON,如下所示:
{"success":false,"data":{"message":"Wrong user credentials.","errorCode":48}}
我正在使用Android Studio上的Volley库。
我已经完成的工作:
-
我在PostMan上尝试了整个过程。以下是我的结论:
- POST 请求有效,GET 请求无效。
- 需要参数。
- 请求头中没有任何内容(除了“自动生成”的内容)Postman的请求头。
- 请求体中没有任何内容[Postman的请求体][2]。
- 即使使用错误的凭据,也会发送JSON响应。只要参数正确,响应的内容就会改变。
- 我尝试了HTTP和HTTPS两种方式,这两种方式在这里都可以正常工作[HTTPS也一样正常工作][3]。
-
我在APP的
build.gradle
中安装了Volley库依赖[build.gradle中的Volley依赖][4]。 -
在我的
Manifest.xml
中授权了Internet和Network State[manifest.xml中的INTERNET和NETWORK STATE][5]。 -
创建了一个非常基本的登录界面作为主要活动。
-
单击按钮后,将我进行的测试。
这里是我执行的3个测试:
a. 使用StringRequest(是的,我想要一个POST请求,但不需要在请求体中添加任何内容,我认为保持简单可能是一个好主意)。我在这里进行了大量的测试,与下一个主题JsonObjectRequest一样。
b. 使用JsonObjectRequest(对这个做了很多尝试!我认为我真的尽力了,尝试了StackOverflow和其他地方找到的所有方法)。除其他事项外,尝试覆盖BodyContent、Headers、Body等。
c. 使用一个新的“帮助”类,该类扩展了Request<JSONObject>,正如我在[这里][6]所读到的。
我的问题是:
我找不到一种方法来将参数传递给POST的URL...在调试时,我得到的是Volley的“mUrl”作为基本URL(https://logintest.moveon.pro/),而不是带有添加参数的URL(https://logintest.moveon.pro/?rest_route=/simple-jwt-login/v1/auth&email=Email&password=Password)。
以下是我的代码...
我在这里使用了一个愚蠢的“if”语句,以测试不同的方法,不要责怪我太多;-)...
并且想要发送的参数中存在很多冗余。
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText usernameEditText = findViewById(R.id.username);
final EditText passwordEditText = findViewById(R.id.password);
final Button loginButton = findViewById(R.id.login);
final ProgressBar loadingProgressBar = findViewById(R.id.loading);
loginButton.setOnClickListener(new View.OnClickListener() {
private static final String URL_LOGIN = "http://logintest.moveon.pro";
private static final String route = "/simple-jwt-login/v1/auth";
@Override
public void onClick(View v) {
final JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("rest_route", "/simple-jwt-login/v1/auth");
jsonObject.put("email", "john@domain.com");
jsonObject.put("password", "ghjghjk");
} catch (JSONException e) {
e.printStackTrace();
}
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
String url = "http://logintest.moveon.pro/";
int test = 3;
if (test == 0) {
StringRequest sr = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.e("HttpClient", "success! response: " + response.toString());
usernameEditText.setText("Response is: " + response.toString().substring(0, 500));
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
usernameEditText.setText("That didn't work!");
Log.e("HttpClient", "error: " + error.toString());
}
}) {
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "asdasd");
params.put("password", "ghjghjk");
return params;
}
@Override
public byte[] getBody() throws AuthFailureError {
HashMap<String, String> params2 = new HashMap<String, String>();
params2.put("rest_route", "/simple-jwt-login/v1/auth");
params2.put("email", "john@domain.com");
params2.put("password", "ghjghjk");
return new JSONObject(params2).toString().getBytes();
}
@Override
public String getBodyContentType() {
return "application/json; charset=UTF-8";
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json; charset=UTF-8");
return headers;
}
};
queue.add(sr);
} else if (test == 1) {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "asdasd");
params.put("password", "ghjghjk");
JSONObject parameters = new JSONObject(params);
JsonObjectRequest stringRequest1 = new JsonObject
<details>
<summary>英文:</summary>
I need to make a HTTPS **POST** with urlencoded parameters like this :
> https://logintest.moveon.pro/?rest_route=/simple-jwt-login/v1/auth&email=Email&password=Password
And get in return a JSON like this :
{"success":false,"data":{"message":"Wrong user credentials.","errorCode":48}}
I am using Volley library on Android Studio.
**What I have done :**
1. I have tried the complete process on PostMan. Here are the conclusion :
- POST works, GET does not.
- Parameters are needed
- There is NOTHING in header (on request, except the "auto-generated" ones)[Postman of Header][1]
- There is NOTHING in body (on request)[Postman of Body][2]
- Checked that even with incorrect credentials, a JSON answer is sent. Just the content of the answer will change if the parameters are correct.
- I tried with both, HTTP & HTTPS, both work the same here.[HTTPS working just as fine][3]
2. Installed Volley in the APP build.gradle
[build.gradle Volley dependenciy][4]
3. Authorized the Internet & Network State in my Manifest.xml
[manifest.xml INTERNET & NETWROK STATE][5]
4. Did a very basic login Screen as main activity
5. When clicking, direct me on my TESTs I've done.
Here are my 3 tests performed :
a. With StringRequest (Yes, I want a POST, but don't need anything in the request body, I thought it could be an idea to go simple). I did a great deal of testing here, same as with the next subject, the JsonObjectRequest.
b. With a JsonObjectRequest (Did soooooo many tries with this one ! I think I really tried all I could find on StackOverflow... and others...).
Among other things trying to override BodyContent, Headers, Body, etc...
c. With a new "helping" class which extends the Request<JSONObject>. as I read [here][6].
**What is my problem :**
I can't find a way to pass my parameters to the POST url... When debugging I get the "mUrl" of Volley as the basic URL (https://logintest.moveon.pro/) and not the one with added parameters (https://logintest.moveon.pro/?rest_route=/simple-jwt-login/v1/auth&email=Email&password=Password).
Here is my code...
I used a stupid "if" in order to test the different approaches, don't blame me too hard on this ;-)...
And there is a LOT of redundancy in the parameters wanting to be sent.
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
/**
* Logcat tag
*/
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText usernameEditText = findViewById(R.id.username);
final EditText passwordEditText = findViewById(R.id.password);
final Button loginButton = findViewById(R.id.login);
final ProgressBar loadingProgressBar = findViewById(R.id.loading);
loginButton.setOnClickListener(new View.OnClickListener() {
private static final String URL_LOGIN = "http://logintest.moveon.pro";
//private static final String URL_LOGIN = "http://logintest.moveon.pro/?rest_route=/simple-jwt-login/v1/auth&email=Email&password=Password";
private static final String route = "/simple-jwt-login/v1/auth";
@Override
public void onClick(View v) {
// Build the request payload -- tried not working better
final JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("rest_route", "/simple-jwt-login/v1/auth");
jsonObject.put("email", "john@domain.com");
jsonObject.put("password", "ghjghjk");
} catch (JSONException e) {
e.printStackTrace();
}
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
//Tried different ways of sending the request :
//String url = "http://logintest.moveon.pro/?rest_route=/simple-jwt-login/v1/auth&email=Email&password=Password";
//String url = "http://logintest.moveon.pro/wp-json/?rest_route=/simple-jwt-login/v1/auth&email=Email&password=Password";
String url = "http://logintest.moveon.pro/";
int test = 3;
if (test == 0) {
// Request a string response from the provided URL.
StringRequest sr = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.e("HttpClient", "success! response: " + response.toString());
// Display the first 500 characters of the response string.
usernameEditText.setText("Response is: " + response.toString().substring(0, 500));
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
usernameEditText.setText("That didn't work!");
Log.e("HttpClient", "error: " + error.toString());
}
}) {
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "asdasd");
params.put("password", "ghjghjk");
return params;
}
//Tried with adding params in Body... but not working better
@Override
public byte[] getBody() throws AuthFailureError {
HashMap<String, String> params2 = new HashMap<String, String>();
params2.put("rest_route", "/simple-jwt-login/v1/auth");
params2.put("email", "john@domain.com");
params2.put("password", "ghjghjk");
return new JSONObject(params2).toString().getBytes();
}
//Tried defining the Body content in different ways... but not working better
@Override
public String getBodyContentType() {
return "application/json; charset=UTF-8";
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
//headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//headers.put("Content-Type","application/x-www-form-urlencoded");
headers.put("Content-Type", "application/json; charset=UTF-8");
return headers;
}
};
// Add the request to the RequestQueue.
queue.add(sr);
} else if (test == 1) {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "asdasd");
params.put("password", "ghjghjk");
JSONObject parameters = new JSONObject(params);
// Request a string response from the provided URL.
JsonObjectRequest stringRequest1 = new JsonObjectRequest(Request.Method.POST, url, parameters,
new Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// Display the first 500 characters of the response string.
usernameEditText.setText("Response is: " + response.toString().substring(0, 500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
usernameEditText.setText("That didn't work!");
}
}) {
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "asdasd");
params.put("password", "ghjghjk");
return params;
}
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
//headers.put("Content-Type", "application/json");
return headers;
}
};
// Add the request to the RequestQueue.
queue.add(stringRequest1);
} else if (test == 3) {
Map<String, String> params = new HashMap();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "john@domain.com");
params.put("password", "ghjghjk");
CustomVolleyRequest strReq = new CustomVolleyRequest(Request.Method.POST, url, params, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Log.e("HttpClient", "success! response: " + response.toString());
// Display the first 500 characters of the response string.
usernameEditText.setText("Response is: " + response.toString().substring(0, 500));
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
usernameEditText.setText("That didn't work!");
Log.e("HttpClient", "error: " + error.toString());
}
}) ;
}
}
});
}
}
Also here is the "helper" class I took form the post already mentioned :
package com.example.logintest;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import com.android.volley.NetworkResponse;
import com.android.volley.ParseError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.toolbox.HttpHeaderParser;
public class CustomVolleyRequest extends Request<JSONObject> {
private Listener<JSONObject> listener;
private Map<String, String> params;
public CustomVolleyRequest(String url, Map<String, String> params, Listener<JSONObject> responseListener, ErrorListener errorListener) {
super(Method.GET, url, errorListener);
this.listener = responseListener;
this.params = params;
}
public CustomVolleyRequest(int method, String url, Map<String, String> params, Listener<JSONObject> responseListener, ErrorListener errorListener) {
super(method, url, errorListener);
this.listener = responseListener;
this.params = params;
}
protected Map<String, String> getParams()
throws com.android.volley.AuthFailureError {
return params;
}
@Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONObject(jsonString),
HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JSONException je) {
return Response.error(new ParseError(je));
}
}
@Override
protected void deliverResponse(JSONObject response) {
// TODO Auto-generated method stub
listener.onResponse(response);
}
}
[1]: https://i.stack.imgur.com/xT73k.png
[2]: https://i.stack.imgur.com/uaLkd.png
[3]: https://i.stack.imgur.com/sCDZT.png
[4]: https://i.stack.imgur.com/JBfY8.png
[5]: https://i.stack.imgur.com/KuSOv.png
[6]: https://stackoverflow.com/questions/24926446/android-volley-post-sending-parameters-is-always-null
</details>
# 答案1
**得分**: 0
你可以这样发送一个x-www-form-urlencoded请求:
- 请求头:Content-Type: application/x-www-form-urlencoded
- 请求体:rest_route=/simple-jwt-login/v1/auth&password=<YOUR_PASSWORD>&email=<YOUR_EMAIL>。(用正确的凭据替换占位符)。
你可以参考这个链接:https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
让我知道你的更新 =)
<details>
<summary>英文:</summary>
you can send a x-www-form-urlencoded request in this way:
- request header: Content-Type: application/x-www-form-urlencoded
- request body: rest_route=/simple-jwt-login/v1/auth&password=<YOUR_PASSWORD>&email=<YOUR_EMAIL>. (replace the placeholder by the correct credentials).
you can check this for reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
let me know your update =)
</details>
# 答案2
**得分**: 0
这是我的工作代码。
问题出现在API中,即使语法正确,它仍然返回400代码。
当我通过POSTMAN发现这个问题后,我寻找了一种仍然可以从我的POST请求中获取响应体的方法,使用Volley错误返回。
我找到了这个帖子[这里][1],我将它添加到我的解决方案中,简化了它到最大限度,这是结果:
```java
package com.example.logintest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.ServerError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
/**
* Logcat标签
*/
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText usernameEditText = findViewById(R.id.username);
final EditText passwordEditText = findViewById(R.id.password);
final Button loginButton = findViewById(R.id.login);
final ProgressBar loadingProgressBar = findViewById(R.id.loading);
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 实例化请求队列。
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
String url = "https://logintest.moveon.pro/";
// 从提供的URL请求字符串响应。
StringRequest sr = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.e("HttpClient", "成功!响应:" + response.toString());
// 显示响应字符串的前500个字符。
usernameEditText.setText("响应是:" + response.toString().substring(0, 500));
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
usernameEditText.setText("这不起作用!");
// 从f605da3版本开始,以下内容应该有效
NetworkResponse response = error.networkResponse;
if (error instanceof ServerError && response != null) {
try {
String res = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, "utf-8"));
// 现在您可以使用任何反序列化器来理解数据
JSONObject obj = new JSONObject(res);
usernameEditText.setText(usernameEditText.getText() + res);
} catch (UnsupportedEncodingException e1) {
// 无法正确解码数据为字符串
e1.printStackTrace();
} catch (JSONException e2) {
// 返回的数据不是JSONObject?
e2.printStackTrace();
}
}
Log.e("HttpClient", "错误:" + error.toString());
}
}) {
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "dummy@gmail.com");
params.put("password", "935jIDan^4S@$rAFLw4w@!$Z");
return params;
}
};
// 将请求添加到请求队列中。
queue.add(sr);
}
});
}
}
希望这对某人有所帮助...
最好的问候,愿您编程愉快!!!
英文:
so here is my working code.
The problem was lying into the API which was returning 400 code even though the syntax was correct.
When I found this out thanks to POSTMAN, I looked for a way to still get the body answer from my POST, using Volley Error return.
I found this post here which I added to my solution '0', simplified it at maximum, and here is the result :
package com.example.logintest;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.ServerError;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HttpHeaderParser;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
public class MainActivity extends AppCompatActivity {
/**
* Logcat tag
*/
private static final String TAG = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText usernameEditText = findViewById(R.id.username);
final EditText passwordEditText = findViewById(R.id.password);
final Button loginButton = findViewById(R.id.login);
final ProgressBar loadingProgressBar = findViewById(R.id.loading);
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
String url = "https://logintest.moveon.pro/";
// Request a string response from the provided URL.
StringRequest sr = new StringRequest(Request.Method.POST, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Log.e("HttpClient", "success! response: " + response.toString());
// Display the first 500 characters of the response string.
usernameEditText.setText("Response is: " + response.toString().substring(0, 500));
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
usernameEditText.setText("That didn't work!");
// As of f605da3 the following should work
NetworkResponse response = error.networkResponse;
if (error instanceof ServerError && response != null) {
try {
String res = new String(response.data,
HttpHeaderParser.parseCharset(response.headers, "utf-8"));
// Now you can use any deserializer to make sense of data
JSONObject obj = new JSONObject(res);
usernameEditText.setText(usernameEditText.getText() + res);
} catch (UnsupportedEncodingException e1) {
// Couldn't properly decode data to string
e1.printStackTrace();
} catch (JSONException e2) {
// returned data is not JSONObject?
e2.printStackTrace();
}
}
Log.e("HttpClient", "error: " + error.toString());
}
}) {
@Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("rest_route", "/simple-jwt-login/v1/auth");
params.put("email", "dummy@gmail.com");
params.put("password", "935jIDan^4S@$rAFLw4w@!$Z");
return params;
}
};
// Add the request to the RequestQueue.
queue.add(sr);
}
});
}
}
Hope this will help someone...
Best regards, and happy coding !!!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论