取通过body传输的postdata数据

本文探讨了在Java Servlet或Spring MVC中通过body传输POST数据时遇到的问题,并提供了解决方案。介绍了如何避免调用getParameter方法导致无法通过输入流获取POST数据的情况。

 

    目前基于rest风格的很多API开始使用通过body data来传输来代替之前的key-value传输方式。在java servlet或者springmvc中可以通过如下代码来获取并图片通过流方式传输的数据:

 

1 InputStream is= null; String contentStr=""
2 try {
3      is = request.getInputStream();
4           contentStr= IOUtils.toString(is, "utf-8");
5    catch (IOException e) {
6       e.printStackTrace(); 
7   }


 

 

单纯的如上代码可以获取通过POST或PUT等方法传输的数据,但有时候也有例,如果你现在有如下请求的时候:

 

POST http://127.0.0.1:8085/test?id=12564564654

POST data:

01001512a101a203a303a

 

可以看到这里不但会通过post data流的方式发送数据,同时也通过key-value发送了数据,那现在的代码是什么样的呢?如下:

01 @RequestMapping(value = "posttest", method = RequestMethod.POST) 
02 @ResponseBody 
03 public String test(HttpServletRequest request,@RequestParam(value = "id") String id ) {
04      InputStream is= null;     
05      String contentStr="";     
06      try {         
07          is = request.getInputStream();         
08          contentStr= IOUtils.toString(is, "utf-8");     
09          catch (IOException e) { 
10                  e.printStackTrace();     
11          }     
12          return contentStr; 
13 }


 

通过测试你会发现contentStr中并未获取到任何值,同时也不会报任务错误,这是怎么回事呢?会不会是springmvc的问题?答案是否定的。这个时候获取不到postdata的数据与springmvc没有任务关系,同样的把上面的代码进行修改,如下:


01 @RequestMapping(value = "posttest", method = RequestMethod.POST) 
02 @ResponseBody
03 public String test(HttpServletRequest request) {
04      String id=request.getParameter("id");     
05      InputStream is= null;     
06      String contentStr="";     
07      try 
08              is = request.getInputStream();         
09              contentStr= IOUtils.toString(is, "utf-8");     
10          catch (IOException e) {
11                   e.printStackTrace();     
12          }     
13          return contentStr; 
14 }


 

经过测试getInputStream仍然没有数据。

 

那问题出在哪呢?经过查找终于找到问了问答的原因,答案在servlet规范中:

3.1.1 When Parameters Are Available
The following are the conditions that mustbe met before post form data will be 
populated to the parameter set:
1. The request is an HTTP or HTTPS request.
2.  The HTTP method is POST.
3.  The content type is application/x-www-form-urlencoded.
4.  The servlet has made an initial call of any of the getParameterfamily of methods 
on the request object.
If the conditions are not met and the post form data is not included in the parameter 
set, the post data must still be available to the servlet via the request object’s input 
stream. If the conditions are met, post form data will no longer be available for 
reading directly from the request object’s input stream.

 

经过翻译servlet上面一段规范如下:

根据Servlet规范,如果同时满足下列条件,则请求体(Entity)中的表单数据,将被填充到request的parameter集合中(request.getParameter系列方法可以读取相关数据):
1 这是一个HTTP/HTTPS请求
2 请求方法是POST(querystring无论是否POST都将被设置到parameter中)
3 请求的类型(Content-Type头)是application/x-www-form-urlencoded
4 Servlet调用了getParameter系列方法


如果上述条件没有同时满足,则相关的表单数据不会被设置进request的parameter集合中,相关的数据可以通过request.getInputStream()来访问。反之,如果上述条件均满足,相关的表单数据将不能再通过request.getInputStream()来读取。

 

根据这个规范的说明,当我们在调用request.getParameter(“id”)的方法时,通过post data交的数据(请求体)被填充到了parameter集合中了,所以后面的通过request.getInputStream获取数据流时就为空。通过测试打印断点我们可以看到如下图:

2.jpg

 

原本我们只提交了一个参数id,但是在执行过request.getParameter(“id”)的方法后,我们的parameterNames里就有了两个参数,其中第二个参数的key就是我们通过body请求体传输的数据,值也是body请求体的post data数据。

 

最终这个问题的解决方案是把string id= request.getParameter(“id”);放到request.getInputStream之后,这样就回避了servlet的规范,代码调整后为:


01 @RequestMapping(value = "posttest", method = RequestMethod.POST) 
02 @ResponseBody
03 public String test(HttpServletRequest request) {
04      InputStream is= null;     
05      String contentStr="";     
06      try {         
07          is = request.getInputStream();         
08          contentStr= IOUtils.toString(is, "utf-8");     
09          catch (IOException e) {
10                   e.printStackTrace();     
11              }     
12        String id=request.getParameter("id");     
13   return contentStr; 
14 }


 

在servlet规范中已经说明是post请求时才会有这个获取post提交数据的顺序问题,而在其它的如put中不会出现这种顺序问题。

<think>我们正在讨论JMeter中POST请求的Body数据传输方法。根据引用[1],我们知道在JMeter中传递JSON格式数据是通过在“HTTP请求”组件的“消息体数据”区域中直接输入JSON数据实现的。例如:{"name": "John", "age": 30}。 此外,引用[2]提到,JMeter也支持发送包含文件的HTTP请求,这通常用于文件上传的场景。而引用[3]则提到了在发送请求前对请求体进行加密处理的情况,例如使用AES256加密,并调用开发提供的jar包进行加密。 用户的问题集中在使用Body传输POST请求数据的方法,因此我们需要涵盖普通文本数据(如JSON)、文件上传以及加密数据等场景。 下面将分步骤介绍JMeter中POST请求Body数据传输的几种方法: ### 1. 传递普通文本数据(如JSON、XML等) 在JMeter中,可以通过以下步骤设置POST请求的Body数据: 1. 添加一个**HTTP请求**采样器。 2. 在HTTP请求采样器中,选择请求方法为**POST**。 3. 在**参数**选项卡中,不要填写任何参数(因为我们要使用Body传输)。 4. 切换到**消息体数据**选项卡,在文本框中输入要发送的Body数据,例如JSON字符串:`{"name": "John", "age": 30}`。 5. 同时,需要在**HTTP信息头管理器**中添加相应的Content-Type,例如对于JSON数据,添加`Content-Type: application/json`。 这样,当请求发送时,JMeter会将“消息体数据”中的内容作为请求体发送。 ### 2. 文件上传 如果需要上传文件,可以按照以下步骤操作: 1. 在**HTTP请求**采样器中,选择请求方法为**POST**。 2. 在**文件上传**选项卡中,点击“添加”按钮。 3. 在“文件路径”中选择要上传的文件。 4. 在“参数名称”中填写文件对应的参数名(通常由接口定义)。 5. 在**HTTP信息头管理器**中,通常需要设置`Content-Type: multipart/form-data`,但JMeter在上传文件时会自动设置该请求头以及boundary,所以通常不需要手动设置。 注意:如果同时需要上传文件和其他表单字段,可以在“参数”选项卡中添加其他参数,JMeter会自动将它们作为multipart/form-data的一部分发送。 ### 3. 加密请求体 如果请求体需要加密(如引用[3]所述),可以按照以下步骤操作: 1. 首先,在发送请求前,需要先对请求体进行加密。这可以通过JMeter的**前置处理器**来实现,例如使用**JSR223 PreProcessor**。 2. 在JSR223 PreProcessor中,使用Groovy或其他脚本语言调用加密方法。例如,如果有一个加密的jar包,可以这样使用: ```groovy import com.example.EncryptUtil; // 原始JSON字符串 def json = '{"name": "John", "age": 30}'; // 加密 def encryptedData = EncryptUtil.encryptAES256(json, "your-secret-key"); // 将加密后的字符串保存到变量中 vars.put("encryptedBody", encryptedData); ``` 3. 在**HTTP请求**采样器的“消息体数据”中,使用变量引用加密后的内容:`${encryptedBody}`。 4. 同时,根据加密后的数据格式,设置相应的Content-Type(如可能是`application/octet-stream`或自定义类型)。 ### 4. 使用参数化动态构建Body 在实际测试中,我们经常需要动态生成Body数据。可以使用JMeter的变量和函数来实现: 1. 在“消息体数据”中,可以使用JMeter变量和函数构造动态内容。例如: ``` { "name": "${name}", "age": ${age} } ``` 其中,`${name}`和`${age}`是变量,可以在测试运行前通过CSV数据文件设置、用户定义的变量或前置处理器生成。 ### 注意事项 - 设置正确的Content-Type:在**HTTP信息头管理器**中必须设置与Body数据匹配的Content-Type,否则服务器可能无法正确解析请求。 - 编码问题:如果Body中包含非ASCII字符,确保在HTTP请求采样器中设置正确的编码(如UTF-8)。 ### 示例:发送JSON数据HTTP请求配置 1. **HTTP请求**采样器: - 协议:http - 服务器名称或IP:example.com - 方法:POST - 路径:/api/user - 消息体数据: ``` { "name": "John", "age": 30 } ``` 2. **HTTP信息头管理器**: - 添加:`Content-Type: application/json` ### 示例:文件上传配置 1. **HTTP请求**采样器: - 方法:POST - 路径:/upload - 切换到“文件上传”选项卡: - 文件路径:/path/to/file.txt - 参数名称:file (根据接口定义填写) - MIME类型:text/plain (可选,根据文件类型填写) - 在“参数”选项卡中,可以添加其他参数(如: - 名称:description, :This is a test file ) ### 示例:加密请求体配置 1. **JSR223 PreProcessor**(附加到HTTP请求采样器): ```groovy // 假设我们有一个加密工具类 def originalBody = '{"name": "John", "age": 30}'; def encrypted = com.example.CryptoUtil.encryptAES256(originalBody, "secret-key"); vars.put("encryptedBody", encrypted); ``` 2. **HTTP请求**采样器: - 消息体数据:`${encryptedBody}` 3. **HTTP信息头管理器**: - 添加:`Content-Type: application/octet-stream` (根据实际情况设置) 通过以上方法,你可以在JMeter中灵活地处理POST请求的Body数据传输。 §§相关问题§§ 1. JMeter中如何发送XML格式的POST请求? 2. JMeter中如何对HTTP请求进行签名? 3. JMeter中如何读文件内容并作为请求体发送?</think>### JMeter POST请求Body数据传输方法 在JMeter中通过Body传输POST请求数据主要有以下几种方法(根据引用内容整理): #### 1. **直接输入JSON/文本数据**(适用于普通请求) - 在HTTP请求采样器中: 1. 选择请求方法为 **POST** 2. 切换到 **Body Data** 选项卡 3. 直接输入JSON/XML/文本内容 ```json {"username": "test", "password": "123456"} ``` - **必须添加HTTP信息头管理器**: - 设置 `Content-Type: application/json`(JSON数据) - 或 `Content-Type: application/xml`(XML数据) - ✅ 优势:简单快捷,适合静态数据 > 引用[1]确认:_"在消息体数据区域中输入JSON数据内容,例如:{"name": "John", "age": 30}"_[^1] #### 2. **文件上传**(适用于文件传输) - 在HTTP请求采样器中: 1. 选择请求方法为 **POST** 2. 切换到 **Files Upload** 选项卡 3. 添加文件路径和参数名(如 `file`) 4. 设置MIME类型(如 `image/png`) - **自动生成multipart/form-data头** > 引用[2]说明:_"JMeter支持发送包含文件的HTTP请求,自动处理multipart格式"[^2]_ #### 3. **参数化动态数据**(适用于测试数据驱动) - **使用变量**: ```json {"user": "${username}", "token": "${token}"} ``` - **配合CSV数据文件**: 1. 添加 **CSV Data Set Config** 2. 在Body Data中引用变量名 ```json {"id": ${user_id}, "role": "${role}"} ``` #### 4. **加密数据处理**(适用于安全接口) - 通过 **JSR223 PreProcessor** 脚本加密: ```groovy import com.example.EncryptUtil // 引用开发提供的jar def rawBody = '{"data": "test"}' vars.put("encryptedBody", EncryptUtil.aes256(rawBody)) ``` - 在Body Data中使用加密结果: ``` ${encryptedBody} ``` > 引用[3]示例:_"jmeter调用加密jar包对json参数进行加密"[^3]_ #### 5. **从文件读Body内容** - 使用 **__FileToString()** 函数: ``` ${__FileToString(/path/data.json,,)} ``` #### 🔧 必要配置 1. **HTTP信息头管理器**(必须): - JSON请求:`Content-Type: application/json` - XML请求:`Content-Type: application/xml` - 文件上传:JMeter自动生成`multipart/form-data` 2. **编码设置**: - 在HTTP请求中勾选 **Use multipart/form-data**(仅文件上传时需要) - 设置 **Content encoding**(如UTF-8) ### 操作示例 ```mermaid graph TD A[创建线程组] --> B[添加HTTP请求] B --> C{数据类型} C -->|JSON/XML| D[在Body Data直接输入] C -->|文件| E[Files Upload选项卡] C -->|加密数据| F[JSR223前置处理器] D & E & F --> G[添加HTTP信息头管理器] G --> H[设置Content-Type] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值