Android Volley调用REST API持续返回400错误求助
Hey there, let's break down why you're hitting that frustrating 400 error with your Volley PUT request—this is super common when working with custom REST APIs, so let's walk through the most likely fixes step by step.
1. First: Validate Your API Endpoint & HTTP Method Match
A 400 error often means your request doesn't align with what the API expects. Let's start here:
- Double-check if your REST API actually accepts
PUTrequests at the exact URLhttp://***.**.***.***:8080/engAppApi/webservices/engineerTable/. Many APIs usePOSTfor creating new resources and reservePUTfor updating existing ones (which usually requires an ID in the URL, like/engineerTable/123). If you're trying to add a new entry to the database, swapRequest.Method.PUTforRequest.Method.POSTand test again. - Test the endpoint directly with a tool like Postman first: send the same JSON payload, headers, and method to the URL. If Postman also returns a 400, the issue is with your API or payload—not your Android code.
2. Validate Your JSON Payload
Your API might be rejecting the JSON because of missing fields, wrong data types, or mismatched field names. Let's dig into this:
- Check if variables like
durationHours,downtimeMinsare numeric (integers/floats) or strings. If the API expects numbers but you're passing strings, that'll trigger a 400. - Ensure
createdTimestampuses the exact date format your API requires (e.g., ISO 8601 like2024-05-20T14:30:00.000Z). - You already log the JSON with
Log.i("json", jsonObject.toString());—copy that output into Postman's request body and see if the API gives a specific error message (like "missing required field 'workOrderNumber'").
3. Simplify Your Volley Request (Remove Unnecessary Overrides)
You've overridden getBody(), getBodyContentType(), and getHeaders()—but Volley's JsonObjectRequest handles JSON bodies and content types by default. These overrides can introduce encoding or formatting issues. Try this simplified version:
private void sendRequest() { RequestQueue queue = Volley.newRequestQueue(this); String url = "http://***.**.***.***:8080/engAppApi/webservices/engineerTable/"; final JSONObject jsonObject = new JSONObject(); try { jsonObject.put("machineType", machineType); jsonObject.put("workOrderNumber", workOrderNumber); jsonObject.put("employeeName", employee); jsonObject.put("activity", activity); jsonObject.put("durationHours", durationHours); jsonObject.put("durationMins", durationMins); jsonObject.put("downtimeHours", downTimeHours); jsonObject.put("downtimeMins", downTimeMins); jsonObject.put("details", details); jsonObject.put("createdTimestamp", currentDateandTime); } catch (JSONException e) { e.printStackTrace(); Toast.makeText(this, "Failed to build request payload", Toast.LENGTH_SHORT).show(); return; } JsonObjectRequest request = new JsonObjectRequest( Request.Method.PUT, // Swap to POST if needed url, jsonObject, response -> { Log.d("Response", response.toString()); Toast.makeText(MainActivity.this, "Success: " + response.toString(), Toast.LENGTH_SHORT).show(); }, error -> { if (error instanceof ServerError && error.networkResponse != null) { try { // Get the actual error message from the API String errorResponse = new String( error.networkResponse.data, HttpHeaderParser.parseCharset(error.networkResponse.headers, "utf-8") ); Log.e("API Error", errorResponse); Toast.makeText(MainActivity.this, "API Error: " + errorResponse, Toast.LENGTH_LONG).show(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); Toast.makeText(MainActivity.this, "Failed to parse error", Toast.LENGTH_SHORT).show(); } } else { Toast.makeText(MainActivity.this, "Request failed: " + error.getMessage(), Toast.LENGTH_SHORT).show(); } } ) { @Override public Map<String, String> getHeaders() { Map<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json;charset=utf-8"); headers.put("securityToken", "Good Token"); return headers; } }; queue.add(request); }
Key changes:
- Removed
getBody()andgetBodyContentType()overrides—Volley handles JSON serialization correctly by default. - Added error handling to log the API's actual error response (this will tell you exactly what's wrong).
4. Check for Missing Required Fields
Make sure none of your variables are null or empty when you add them to the JSONObject. Add quick checks before building the JSON:
if (machineType == null || machineType.trim().isEmpty()) { Toast.makeText(this, "Machine type is required", Toast.LENGTH_SHORT).show(); return; } // Repeat this check for all fields the API marks as required
5. Verify Network Access
If you're testing on a local network:
- Ensure your Android device/emulator can reach the API server (ping the IP address from your device, or check firewall settings on the server).
- For API level 28+, enable cleartext traffic in your
AndroidManifest.xml(since you're using HTTP, not HTTPS):
<application ... android:usesCleartextTraffic="true"> ... </application>
Start with testing the endpoint in Postman—this will immediately tell you if the issue is with your API or your Android code. Once Postman works, the simplified Volley request should follow suit.
内容的提问来源于stack exchange,提问作者Fionnuala

