Java Servlets:区分GET与POST,如何用HttpServletRequest分别提取两类参数?
Let's kick things off with the core distinctions between these two HTTP methods in the context of Java Servlets:
- Data Location: GET parameters are appended to the URL's query string (e.g.,
/path?key=value), while POST parameters are sent in the request body (for content types likeapplication/x-www-form-urlencodedormultipart/form-data). - Length Limits: GET requests are constrained by browser/server URL length limits (typically a few KB), whereas POST requests have no hard length limit (though server configurations may impose caps).
- Caching & Bookmarking: GET requests are cached by browsers and can be bookmarked, since the full request is in the URL. POST requests are not cached and can't be directly bookmarked.
- Security: GET parameters are visible in the URL, so never use GET for sensitive data (like passwords). POST parameters are hidden in the request body, but always use HTTPS to encrypt all data in transit—neither method is secure over plain HTTP.
- Servlet API Behavior: By default,
HttpServletRequest.getParameter()will return the first value for a given key, merging parameters from both the query string (GET) and request body (POST). This is the root of your question: how to separate them.
When the request's Content-Type is application/x-www-form-urlencoded, the POST body uses the same key-value format as the GET query string. The Servlet API doesn't provide a built-in way to separate these, so you'll need to manually parse each source before calling any getParameter*() methods (since calling those will trigger the container to read and merge the request body automatically).
Step 1: Create a Utility Method to Parse Key-Value Strings
This method will handle both query strings and POST body content, decoding URL-encoded values properly:
import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; private Map<String, List<String>> parseKeyValueString(String input) { Map<String, List<String>> paramMap = new HashMap<>(); if (input == null || input.isEmpty()) { return paramMap; } // Split into key-value pairs String[] pairs = input.split("&"); for (String pair : pairs) { // Split into key and value (limit split to 2 to handle values with '=') String[] keyValue = pair.split("=", 2); String key = URLDecoder.decode(keyValue[0], StandardCharsets.UTF_8); String value = keyValue.length > 1 ? URLDecoder.decode(keyValue[1], StandardCharsets.UTF_8) : ""; // Add to map (handle multiple values for the same key) paramMap.computeIfAbsent(key, k -> new ArrayList<>()).add(value); } return paramMap; }
Step 2: Extract GET and POST Parameters Separately in Your Servlet
In your doPost method, read the query string and request body directly, then parse them with the utility method:
import java.io.BufferedReader; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/path") public class ParameterSeparationServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Set character encoding FIRST to avoid garbled text request.setCharacterEncoding("UTF-8"); response.setContentType("text/plain; charset=UTF-8"); // 1. Extract GET parameters from the query string String queryString = request.getQueryString(); Map<String, List<String>> getParams = parseKeyValueString(queryString); // 2. Extract POST parameters from the request body StringBuilder bodyContent = new StringBuilder(); try (BufferedReader reader = request.getReader()) { String line; while ((line = reader.readLine()) != null) { bodyContent.append(line); } } String postBody = bodyContent.toString(); Map<String, List<String>> postParams = parseKeyValueString(postBody); // Example usage: Get the first value for a parameter from each source String getFirstName = getParams.getOrDefault("first_name", Collections.emptyList()) .stream() .findFirst() .orElse(""); String postedFirstName = postParams.getOrDefault("first_name", Collections.emptyList()) .stream() .findFirst() .orElse(""); // Output results response.getWriter().println("GET Parameters: " + getParams); response.getWriter().println("POST Parameters: " + postParams); response.getWriter().println("First name from GET: " + getFirstName); response.getWriter().println("First name from POST: " + postedFirstName); } // Include the parseKeyValueString method here private Map<String, List<String>> parseKeyValueString(String input) { // ... (as defined earlier) } }
Critical Notes
- Don't Call
getParameter()First: If you invoke anygetParameter(),getParameterMap(), orgetParameterValues()method before reading the request body, the Servlet container will consume the request body to merge parameters, and callingrequest.getReader()will throw anIllegalStateException. - Encoding: Always set
request.setCharacterEncoding("UTF-8")before reading the request body or query string to ensure proper decoding of non-ASCII characters. - Multiple Values: The utility method handles multiple values for the same key (e.g.,
first_name=foo&first_name=bar) by storing them in aList, which aligns with HTTP standards.
内容的提问来源于stack exchange,提问作者Jonathon

