Get和Post各种编码方式和获取参数的问题

2024-02-07 15:38

本文主要是介绍Get和Post各种编码方式和获取参数的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Get和Post各种编码方式和获取参数的问题

  做后端开发,会跟各种请求打交道,Get或者Post甚至其他,而就Get和Post不同的编码方式和content-type提交也有许多的不同,在开发过程中,经常遇到参数接收不到的问题,无论是原生servlet还是springboot框架,都有到过这种问题。这篇文中就这些问题,通过分析,希望能让自己能更进一步的了解HTTP请求和参数接收相关的原理。

Get请求

  Get请求比较简单,请求的参数为[key=value],通过&连接起来,一般被称为查询字符串(Query String),例如:http://127.0.0.1/test?name=strive&age=23,参数为:name=strive&age=23.

GET /get?name=strive HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: same-origin
Referer: http://localhost:8080/getAndPostIndex
Accept-Encoding: gzip, deflate, br

  其实我们只需要看/get?name=strive即查询参数,GET请求参数是被存放在QueryString 中的,这种在我们后台是可以通过request.getParameter() 获取请求参数的。

POST请求

  下面我们来看POST请求,POST请求的方式比Get复杂,它参数的存放位置是和Content-Type 有关系的,具体有什么关系,继续往下看。

Content-Type为application/x-www-form-urlencoded
POST /postUrl HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 11
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: same-origin
Referer: http://localhost:8080/getAndPostIndex
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,ko;q=0.8,en;q=0.7
Form Data
name=strive

  这种方式提交的参数放在了以[key=value]方式存在了请求体中,这种在我们后台是也是可以通过request.getParameter() 获取请求参数的。

Content-Type为multipart/form-data
POST /postFileUpload HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 3768
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
#Content-Type为multipart/form-data
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary6A2xLxBKaSvqBvDd
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: same-origin
Referer: http://localhost:8080/getAndPostIndex
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,ko;q=0.8,en;q=0.7
#Request的请求体
Request Payload
------WebKitFormBoundary6A2xLxBKaSvqBvDd
Content-Disposition: form-data; name="file"; filename="Baidu.cer"
Content-Type: application/x-x509-ca-cert
#这里省略了文件的数据
------WebKitFormBoundary6A2xLxBKaSvqBvDd
Content-Disposition: form-data; name="name"
strive
------WebKitFormBoundary6A2xLxBKaSvqBvDd--

  在Content-Type: multipart/form-data 时,而且POST提交的参数存放在了Request Payload,这种请求参数没办法通过request.getParameter() 获取请求参数的。

Content-Type为application/json
POST /postJson HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 13
Accept: */*
Origin: http://localhost:8080
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: cors
Content-Type: application/json
Sec-Fetch-Site: same-origin
Referer: http://localhost:8080/getAndPostIndex
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,ko;q=0.8,en;q=0.7
#Request的请求体
Request Payload
{name:strive}

  在Content-Type: application/json 时,而且POST提交的参数存放在了Request Payload,这种请求参数没办法通过request.getParameter() 获取请求参数的。

Content-Type为text/plain
POST /postPlain HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 13
Cache-Control: max-age=0
Origin: http://localhost:8080
Upgrade-Insecure-Requests: 1
Content-Type: text/plain
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: same-origin
Referer: http://localhost:8080/getAndPostIndex
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,ko;q=0.8,en;q=0.7
#Request的请求体
Request Payload
name=strive

  在Content-Type: text/plain 时,而且POST提交的参数存放在了Request Payload,这种请求参数没办法通过request.getParameter() 获取请求参数的。

POST请求的问题

  从上面的几个请求的报文的例子中我们可以找到一些规律,以application/x-www-form-urlencoded作POST提交的数据,后台是可以通过request.getParameter() 获取请求参数的。而multipart/form-data,application/jsontext/plain作POST提交数据时,后台没法通过request.getParameter() 获取请求参数的。application/x-www-form-urlencoded的参数放在了名为Form Data的请求体中,而其他的则放在了名为Request Payload的请求体中。那是什么原因了?
  解析请求参数的实现源码org.apache.catalina.connector.Request#parseParameters如下:

 protected void parseParameters() {this.parametersParsed = true;Parameters parameters = this.coyoteRequest.getParameters();boolean success = false;try {parameters.setLimit(this.getConnector().getMaxParameterCount());Charset charset = this.getCharset();boolean useBodyEncodingForURI = this.connector.getUseBodyEncodingForURI();parameters.setCharset(charset);if (useBodyEncodingForURI) {parameters.setQueryStringCharset(charset);}parameters.handleQueryParameters();if (this.usingInputStream || this.usingReader) {success = true;return;}//获取请求的contentTypeString contentType = this.getContentType();if (contentType == null) {contentType = "";}int semicolon = contentType.indexOf(59);if (semicolon >= 0) {contentType = contentType.substring(0, semicolon).trim();} else {contentType = contentType.trim();}//处理文件上传if ("multipart/form-data".equals(contentType)) {this.parseParts(false);success = true;return;}if (!this.getConnector().isParseBodyMethod(this.getMethod())) {success = true;return;}if ("application/x-www-form-urlencoded".equals(contentType)) {//如果是这种contenttype则解析int len = this.getContentLength();if (len <= 0) {if ("chunked".equalsIgnoreCase(this.coyoteRequest.getHeader("transfer-encoding"))) {Object var21 = null;Context context;byte[] formData;try {formData = this.readChunkedPostBody();} catch (IllegalStateException var17) {parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);context = this.getContext();if (context != null && context.getLogger().isDebugEnabled()) {context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), var17);}return;} catch (IOException var18) {parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);context = this.getContext();if (context != null && context.getLogger().isDebugEnabled()) {context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), var18);}return;}if (formData != null) {parameters.processParameters(formData, 0, formData.length);}}} else {int maxPostSize = this.connector.getMaxPostSize();Context context;if (maxPostSize >= 0 && len > maxPostSize) {context = this.getContext();if (context != null && context.getLogger().isDebugEnabled()) {context.getLogger().debug(sm.getString("coyoteRequest.postTooLarge"));}this.checkSwallowInput();parameters.setParseFailedReason(FailReason.POST_TOO_LARGE);return;}context = null;byte[] formData;if (len < 8192) {if (this.postData == null) {this.postData = new byte[8192];}formData = this.postData;} else {formData = new byte[len];}try {if (this.readPostBody(formData, len) != len) {parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);return;}} catch (IOException var19) {Context context = this.getContext();if (context != null && context.getLogger().isDebugEnabled()) {context.getLogger().debug(sm.getString("coyoteRequest.parseParameters"), var19);}parameters.setParseFailedReason(FailReason.CLIENT_DISCONNECT);return;}// 处理POST请求参数,把它放到requestparameter map中(即request.getParameterMap获取到的Map,request.getParameter(name)也是从这个Map中获取的)parameters.processParameters(formData, 0, len);}success = true;return;}success = true;} finally {if (!success) {parameters.setParseFailedReason(FailReason.UNKNOWN);}}}

这篇关于Get和Post各种编码方式和获取参数的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/688164

相关文章

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

MySQL 获取字符串长度及注意事项

《MySQL获取字符串长度及注意事项》本文通过实例代码给大家介绍MySQL获取字符串长度及注意事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录mysql 获取字符串长度详解 核心长度函数对比⚠️ 六大关键注意事项1. 字符编码决定字节长度2

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

Python get()函数用法案例详解

《Pythonget()函数用法案例详解》在Python中,get()是字典(dict)类型的内置方法,用于安全地获取字典中指定键对应的值,它的核心作用是避免因访问不存在的键而引发KeyError错... 目录简介基本语法一、用法二、案例:安全访问未知键三、案例:配置参数默认值简介python是一种高级编

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM

IDEA Maven提示:未解析的依赖项的问题及解决

《IDEAMaven提示:未解析的依赖项的问题及解决》:本文主要介绍IDEAMaven提示:未解析的依赖项的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录IDEA Maven提示:未解析的依编程赖项例如总结IDEA Maven提示:未解析的依赖项例如

python3如何找到字典的下标index、获取list中指定元素的位置索引

《python3如何找到字典的下标index、获取list中指定元素的位置索引》:本文主要介绍python3如何找到字典的下标index、获取list中指定元素的位置索引问题,具有很好的参考价值,... 目录enumerate()找到字典的下标 index获取list中指定元素的位置索引总结enumerat

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模