1 什么是GET请求参数
表单GET请求参数是指在HTML表单中通过GET方法提交表单数据时所附带的参数信息。在HTML表单中,可以通过表单元素的name属性来指定表单字段的名称,通过表单元素的value属性来指定表单字段的值。当用户提交表单时,浏览器会将表单字段的名称和值以键值对的形式打包成查询字符串(query string),将查询字符串附加到表单的action URL中作为GET请求的参数信息。
例如,假设一个简单的表单如下所示:
<h1>用户注册</h1>
<form action="/accounts/register" >
<label>姓名:<input type="text" name="name" placeholder="请输入您的姓名"></label><br>
<label>密码:<input type="password" name="password" placeholder="请输入密码"></label><br>
<label>邮箱:<input type="text" name="email" placeholder="请输入邮箱"></label><br>
<label>性别:<input type="text" name="gender" placeholder="输入性别"></label><br>
<input type="submit" value="提交">
</form>
其中,action属性指定表单提交的目标URL。当填写姓名为“Tom”,密码“1234”,邮箱“tom@demo.com”,性别“男”:
并且点击"提交"按钮提交表单时,浏览器将发送一个GET请求到"http://localhost:8089/accounts/register "。
在服务服务器端可以看到如下信息:
显然请求参数信息包含在uri中。
由于我们没有在服务端接收这些参数,并且没有进行适当的处理,所以客户端得到了404错误。
2 解析GET请求参数
解析GET请求参数的过程主要涉及对查询字符串进行解析和处理。通常,服务器端的程序可以通过以下步骤来解析GET请求参数:
1. 获取URL中的查询字符串部分:对于HTTP GET请求,查询字符串部分位于URL中的问号字符(?)之后,可以通过解析URI来获取该部分的内容。
2. 解析查询字符串中的键值对:查询字符串中的键值对通常使用等号(=)连接,键值对之间使用和号(&)连接。可以通过字符串分割和循环遍历来解析键值对。
3. 对键值对的值进行解码:由于URL中的查询字符串部分需要进行URL编码以确保参数值的正确性和安全性,因此在解析时需要对键值对的值进行解码。
综合上述步骤,我们可以使用Java代码实现GET请求参数的解析。解析过程如下所示:
3 解析GET请求参数的方法
首先,添加解析请求参数的方法。
解析请求功能显然是HttpServletRequest对象的职责,重构HttpServletRequest对象,添加解析请求参数的方法:
/** 查询字符串 */
private String queryString;
/** 请求路径 */
private String requestURI;
/** 存储全部参数 */
private HashMap<String, String> parameters = new HashMap<>();
private void parseUri(){
//使用?拆分请求路径和查询字符串. ?是正则特殊字符,需要使用转义字符
String[] parts = uri.split("\\?");
requestURI = parts[0];
queryString = parts[1];
//使用&拆分解析查询字符串
parts = queryString.split("&");
for (String part : parts) {
//使用 = 拆分出 name 和 value
String[] param = part.split("=");
String name = param[0];
String value = param[1];
parameters.put(name, value);
}
System.out.println("解析了参数:"+parameters);
}
在这个解析方法中,假设请求 URI 为 /accounts/register?name=Tom&password=1234&email=tom%40demo.com&gender=%E7%94%B7,解析代码将分解成以下步骤达成目的:
1、使用 split() 方法将 URI 拆分成两个部分,即请求路径和查询字符串。由于 ? 是一个正则特殊字符,因此需要使用转义字符 \\? 进行拆分。因此,parts 数组中将包含 "/accounts/register" 和 " name=Tom&password=1234&email=tom%40demo.com&gender=%E7%94%B7" 两个元素。
2、将parts第一个元素存储到 requestURI 变量中。
3、将parts第二个元素存储到 queryString 变量中。
4、使用 split() 方法将查询字符串 queryString 拆分成多个参数。在这个示例中,使用 & 进行拆分,将得到一个包含四个元素的 parts 数组,分别是 "name=Tom"、" password=1234"、“email=tom%40demo.com”和gender=%E7%94%B7。
5、对于每个参数,使用 split() 方法将参数名称和参数值拆分开。在这个示例中,使用 = 进行拆分。
6、将每个参数名称和参数值存储到 parameters HashMap 中。
7、输出map集合,检查解析是否成功了。
然后,重构解析请求行方法 parseRequestLine:在uri中有?时候调用parseUri()方法对uri中的参数进行进一步的解析:
//解析请求行中的请求参数
if (uri.contains("?")){
parseUri();
}else{
requestURI = uri;
}
4 GET请求编码问题
上述解析URL功能,接收到的中文和特殊字符会出现“乱码”,这个问题并不是乱码,而是HTTP协议通过URL传输数据时候,对特殊字符(中文)进行了编码。
URL参数需要进行编码,是因为URL中只能包含特定的字符集,如字母、数字和一些特殊字符(中文),其他字符如果直接包含在URL中可能会导致URL无法正确解析或者出现意外的结果。因此,为了避免这种情况发生,需要对URL参数进行编码,以便在传输过程中对其进行安全的转换和传递。
URL编码(也称百分号编码或URL转义):将URL参数中的非法字符转换成%xx的形式,其中xx是表示字符ASCII码值的16进制数字,例如空格的ASCII码值是32,因此用%20来表示空格。
下面是一个URL参数编码的示例,假设要传递参数"Hello, World!",使用URL编码后的结果为:"Hello%2C%20World%21"。浏览器在发送数据时候,对数据进行了URL编码,服务端收到的就是这些“乱码”,只要进行对应的解码即可。
5 使用Java API对URL编码数据进行解码
URL解码是将经过编码后的URL参数还原成原始数据的过程。URL解码的目的是为了恢复URL参数的原始含义,使得URL能够正确地被服务器解析和处理。
URL解码(也称百分号解码或URL反转义):将URL参数中的%xx还原成对应的ASCII字符。例如,%20表示空格,将其解码后得到空格字符。
Java API 提供了URLDecoder.decode()方法,对URL编码的数据进行解码:
- 第一个参数为需要解码的URL参数
- 第二个参数为字符编码方式:通常使用UTF-8
- 输出解码后的结果
下面是一个使用Java API对URL编码数据进行解码的示例,假设需要解码的URL参数为"Hello%2C%20World%21":
import java.net.URLDecoder;
public class URLDecoderExample {
public static void main(String[] args) {
try {
String encodedURL = "Hello%2C%20World%21";
String decodedURL = URLDecoder.decode(encodedURL, "UTF-8");
System.out.println("Encoded URL: " + encodedURL);
System.out.println("Decoded URL: " + decodedURL);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果为:
Encoded URL: Hello%2C%20World%21
Decoded URL: Hello, World!
在示例中,首先使用URLDecoder.decode()方法对URL编码的数据进行解码。该方法的第一个参数为需要解码的URL参数,第二个参数为字符编码方式,通常使用UTF-8,最后输出解码后的结果。
6 HttpServletRequest添加参数解码功能
继续重构HttpServletRequest的parseUri方法,将收到的请求数据进行URL解码,这样就可以解决特殊字符以及中文参数解码问题。
代码示意如下:
private void parseUri() throws UnsupportedEncodingException {
//使用?拆分请求路径和查询字符串. ?是正则特殊字符,需要使用转义字符
String[] parts = uri.split("\\?");
requestURI = parts[0];
queryString = parts[1];
//使用&拆分解析查询字符串
parts = queryString.split("&");
for (String part : parts) {
//使用 = 拆分出 name 和 value
String[] param = part.split("=");
String name = param[0];
String value = URLDecoder.decode(param[1], "UTF-8");
parameters.put(name, value);
}
System.out.println("解析了参数:"+parameters);
}
在对接收参数进行URL解码后,在表单中添入中文,在服务端就能接收到正确结果了: