Content-Type引发的服务端收不到HTTP请求参数的问题

2023-05-16

问题现象:

前端POST请求参数已经传过来了,Java后端Debug也能进到请求里,可就是取不到请求参数。


用Chrome 开发者工具可以看到请求的不同:



可以看到请求参数一个在Form Data中,一个在Request Payload中,而且格式也不同。

不同的原因就在于Content-Type设置不同。


HTTP Content-Type

用于标识传输数据的类型。在请求中,Content-Type告诉服务端实际请求内容的类型;在响应中,Content-Type告诉客户端实际返回内容的类型。

HTTP定义的Content-Type类型有近200种(https://www.w3cschool.cn/http/ahkmgfmz.html),其中最常用的是以下三种:

1、application/x-www-form-urlencoded
请求参数在Form Data中,只能上传键值对,并且键值对都是间隔分开的。
参数形式: name1=value1&name2=value2

2、multipart/form-data
请求参数在Request Payload中,既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息。
浏览器将表单内的数据和文件放在一起发送。这种方式会定义一个不可能在数据中出现的字符串作为分隔符,然后用它将各个数据段分开。

3、application/json
请求参数在Request Payload中
参数形式: {key1:value1,key2:value2}


multipart/form-data; boundary=${bound} // 其中${bound}是一个占位符,代表我们规定的分割符,可以自己任意规定,但为了避免和正常文本重复了,尽量要使用复杂一点的内容。

以下是一个multipart/form-data类型的请求:



重点:对应以上三种类型Java服务端获取请求参数的方法也不同(伪代码)

1、application/x-www-form-urlencoded

1)注解@RequestParam(value="name1") String name1
2)注解@ModelAttribute 绑定请求参数到指定对象
3)HttpServletRequest.getParameter("name1")

2、multipart/form-data

流HttpServletRequest.getInputStream()或者HttpServletRequest.getReader()

3、application/json
1)注解@RequestBody
2)流HttpServletRequest.getInputStream()或者HttpServletRequest.getReader()

Tips: request.getParameter()、 request.getInputStream()、request.getReader()这三种方法是有冲突的,因为流只能被读一次,所以只有第一次能取到参数。


原理

那么是什么导致Content-Type类型不同取参方式也不同呢?
由于Tomcat对于Content-Type multipart/form-data(文件上传)和application/x-www-form-urlencoded(POST请求)做了“特殊处理”:
Tomcat的HttpServletRequest类的实现类为org.apache.catalina.connector.Request,而它处理请求参数的方法为protected void parseParameters(),这个方法中对Content-Type multipart/form-data(文件上传)和application/x-www-form-urlencoded(POST请求)做了处理,会解析表单数据放到request parameter map中。其他请求不会解析表单数据,所以通过request.getParameter()是获取不到的。

服务器为什么会对Content-Type application/x-www-form-urlencoded做特殊处理?

因为表单提交数据是名值对的方式,而其他的post请求(Content-Type不是application/x-www-form-urlencoded)数据格式不固定,不一定是名值对的方式,服务器无法知道具体的处理方式,所以只能通过获取原始数据流的方式来进行解析。

tomcat部分源码:

protectedvoid parseParameters() {  
           //省略部分代码......  
           parameters.handleQueryParameters();// 这里是处理url中的参数  
           //省略部分代码......  
           if ("multipart/form-data".equals(contentType)) { // 这里是处理文件上传请求  
                parseParts();  
                success = true;  
                return;  
           }  
           if(!("application/x-www-form-urlencoded".equals(contentType))) {// 这里如果是非POST请求直接返回,不再进行处理  
                success = true;  
                return;  
           }  
           //下面的代码才是处理POST请求参数  
           //省略部分代码......  
           try {  
                if (readPostBody(formData, len)!= len) { // 读取请求体数据  
                    return;  
                }  
           } catch (IOException e) {  
                // Client disconnect  
                if(context.getLogger().isDebugEnabled()) {  
                    context.getLogger().debug(  
                            sm.getString("coyoteRequest.parseParameters"),e);  
                }  
                return;  
           }  
           parameters.processParameters(formData, 0, len); // 处理POST请求参数,把它放到requestparameter map中(即request.getParameterMap获取到的Map,request.getParameter(name)也是从这个Map中获取的)  
           // 省略部分代码......  
}
protected int readPostBody(byte body[], int len)  
   throws IOException {  
   int offset = 0;  
   do {  
	   int inputLen = getStream().read(body, offset, len - offset);  
	   if (inputLen <= 0) {  
			return offset;  
	   }  
	   offset += inputLen;  
   } while ((len - offset) > 0);  
   return len;  
}

实际开发中具体选用哪种Content-Type呢?
Form解析可以直接从Request对象中获取请求参数,这样对象转换与处理相对容易,但在大片JSON数据需要提交时,可能会出现大量的数据拆分与处理工作,另外针对集合类型的处理,也是其比较孱弱的地方。
而Payload的优势是一次可以提交大量JSON字符串,但无法从Request从获取参数,也会受限于JSON解析的深度(尤其是有多层对象级联的情况,最底层的对象几乎无法转换为具体类型)。


其他
jQuery在执行post请求时,会默认设置Content-Type为application/x-www-form-urlencoded,所以服务器能够正确解析,
而使用原生ajax请求时,如果不显示的设置Content-Type,那么默认是text/plain,这时服务器就不知道怎么解析数据了,所以才只能通过获取原始数据流的方式来进行解析请求数据。

jQuery中的dataType指的是预期服务器返回的数据类型,而不是发送的数据类型。如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如 XML MIME 类型就被识别为 XML。这样服务端返回json数据,前端就会获取不到返回值。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Content-Type引发的服务端收不到HTTP请求参数的问题 的相关文章

随机推荐

  • Nginx 和 php-fpm 间的调用关系

    起因 xff1a 之前配置nginx和php fpm 在同机上进行 xff0c 很顺畅 xff0c 近期实验了一下 nginx php mysql 服务分别独立 xff0c 花费了好久才配置好 xff0c 真正理清两者间的联系 这里记录一下
  • Debian11及Alpine Linux中机械硬盘的休眠设定

    hard disk standby 硬盘的待机 hdparm 软件 0 安装 hdparm Debian 中 apt update apt install hdparm Alpine Linux中 apk update apk add hd
  • Centos7.6_1810安装LEMP过程详解(nginx1.14.2+php7.3.1+MariaDB10.3.12)

    经过两天的搜索和学习 xff0c 终于在CentOS7 6 1810版本的最小化安装服务器上完成了LEMP搭建 xff0c 全都用的是最新的稳定版组件 xff08 截止2019 01 26 xff09 xff0c 这里做个记录 xff0c
  • CentOS7.6_1810安装最新版的java11.02和tomcat9.0.14的记录

    所谓的最新版 xff0c 是指到2019 01 28为止的最新版 1 JAVA SE 的安装 java的安装比较简单 xff0c 按照官网的说明 xff0c 下载rpm包安装就好 用wget下载或者在windows系统上下载好rpm包 xf
  • CoreOS Linux 最新2023.5.0版的安装过程-2019-03-28

    注意 xff1a 该操作系统已经被Redhat收购 xff0c 不再更新 xff0c 而是变更为了 Fedora CoreOS系统 xff0c 可看我的文章 xff1a Fedora CoreOS 的裸机安装方法 lggirls的博客 CS
  • 【数据挖掘】5分钟带你了解文本向量化的常见方式

    5分钟带你了解文本向量化的常见方式 1 独特编码模型 2 词袋模型 3 TF IDF模型 4 N gram模型 5 Word2Vec模型 参考资料 文本向量化 将文本信息表示成能够表达文本语义的向量 是 用数值向量来表示文本的语义 词嵌入
  • 裸机安装CoreOS Linux最新2023.5版本后的简单配置(一)

    关于裸机安装方法 xff0c 请看我的博文 CoreOS Linux 最新2023 5 0版的安装过程 2019 03 28 https blog csdn net lggirls article details 88867762 一 更改
  • CoreOS 不重装而使用json文档更新系统配置的方法2019-03-29

    CoreOS在启动过程中 xff0c 先加载内核 xff0c 内核再加一个参数 xff0c 来判断是不是第一次启动 如果第一次启动 xff0c 就执行ignitoin配置 通过研究 xff0c 在 boot coreos下touch一个名称
  • docker 搭建 nginx网站

    一 从网上下载一个html5的单页网站模板 xff0c 解压 xff0c 将文件夹改名为html xff0c 重新压缩为html zip格式 二 在docker宿主机上的自定义网站内容存储文件夹内下载上一步的html zip文档 三 解压
  • docker 搭建多容器LNMP平台遇到的坑

    1 采用什么样的镜像很重要 必须是php 7 3 fpm 采用默认的latest镜像是不行的 xff0c 所以 docker pull php 7 3 fpm 现在有了7 4 fpm docker pull nginx docker pul
  • docker php 扩展安装合集

    在安装SuiteCRM的过程中遇到了 没有zip扩展功能的问题 xff0c 经过一番折腾 xff0c 找到了这个文章 xff0c 在此转发分享 xff0c 希望对其他人有所帮助 1 先进入myphp容器 xff0c 看一下php目前安装了哪
  • SuiteCRM的汉化

    以管理员账户进入suitecrm 选择 admin xff0c 滚动页面 xff0c 找到下面 Developer Tools下的Module Loader项目 上传下载好的汉化包 点击下载后在该项目上出现的 INSTALL xff0c 完
  • docker 搭建odoo ERP服务器

    按照官方教程来操作即可 xff1a https hub docker com odoo 环境 xff1a Linux CoreNAS 4 19 25 coreos 1 SMP Sat Mar 9 01 05 06 00 2019 x86 6
  • 使用docker 搭建 ftp文件服务器

    A 使用fauria vsftpd创建ftp 这个最简单 xff0c 推荐使用 docker run itd name ftp h ftp p 20 20 p 21 21 p 21100 21110 21100 21110 v home v
  • 为Coreos系统安装docker-compose 命令

    不知为什么 xff0c 官方版的CoreOS操作系统安装了docker 但就是没有docker compose命令 xff0c 使得通过 yaml配置容器的方式无法进行 xff0c 因而需要进行手动安装这一工具 在CoreOS中 xff0c
  • 用笔记本做路由器共享4G流量

    有一张电信的4G手机卡 xff0c 每个月40G的高速流量 xff0c 但总是用不完 xff0c 所以考虑将手机开放热点 xff0c 用家里的废弃笔记本装CentOS7系统 xff0c 做个NAT xff0c 再接一个TP link 5口交
  • 【AIGC】手把手使用扩散模型从文本生成图像

    手把手使用扩散模型从文本生成图像 从 DALLE 到Stable Diffusion使用diffusers package从文本prompt生成图像参考资料 在这篇文章中 xff0c 我们将手把手展示如何使用Hugging Face的dif
  • 验证win10下解决某些word文档提示”内存或磁盘空间不足”的几种方法

    验证win10下解决某些word文档提示 内存或磁盘空间不足 的几种方法 编者 xff1a 李国帅 qq xff1a 9611153 微信lgs9611153 时间 xff1a 2020 03 11 背景原因 前段时间把系统升级到了win1
  • windows下配置apache+php环境

    PHP 配置PHP7 43 Apache2 4 环境 首先讲一下电脑环境与版本 电脑 window10 X64 Apache httpd 2 4 33 o102o x64 vc14 r2 zip xff08 官网下载http www apa
  • Content-Type引发的服务端收不到HTTP请求参数的问题

    问题现象 xff1a 前端POST请求参数已经传过来了 xff0c Java后端Debug也能进到请求里 xff0c 可就是取不到请求参数 用Chrome 开发者工具可以看到请求的不同 xff1a 可以看到请求参数一个在Form Data中