Java—RestTemplate发送POST请求之formData形式&请求之带header,入参为json格式

本文介绍了如何使用Spring Boot通过RestTemplate实现POST请求,包括formData形式的数据提交和带有header的JSON参数传递。具体展示了如何构造MultiValueMap和HttpEntity,以及调用接口并返回响应结果。
package xxxxxx;

import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;


@Service
public class DemoService {

    @Resource
    private RestTemplate restTemplate;


    //RestTemplate发送POST请求之formData形式
    public String testCall(){
        MultiValueMap<String, Object> reqMap = new LinkedMultiValueMap<>();;
        reqMap.add("name","huhansan");
        reqMap.add("sex","man");
        return restTemplate.postForEntity("http://localhost:8888/postwithpara", reqMap, String.class).getBody();

    }

    //RestTemplate发送POST请求之带header,入参为json格式
    public String testApi() throws JSONException {
        //添加参数
        JSONObject para = new JSONObject();
        para.put("templateCode", "7568fdc4b8c944e6aed32590467c17fb");
        para.put("tabOptions", 0);
        HttpHeaders headers = new HttpHeaders();
        headers.add("token", "bedfe4c9fa5140839a5f8f10eb05bcca");
        HttpEntity<String> requestParam = new HttpEntity<>(para.toString(), headers);
        String url = "XXXXXXXXX";
        String res = restTemplate.postForEntity(url, requestParam, String.class).getBody();
        System.out.println(res.toString());
        return  res;

    }

}

&lt;think&gt; 我们正在解决的是POST请求自动变为JSON格式且不自动生成boundary的问题。根据用户描述,他可能遇到了以下情况: 1. 在发送POST请求时,希望使用multipart/form-data格式(包含boundary),但实际请求被自动转成了application/json格式。 2. 或者,在设置header时,手动设置了Content-Type为multipart/form-data,但没有设置boundary,导致请求失败。 回顾之前的对话,用户在使用uni.uploadFile时,由于手动设置Content-Type导致boundary缺失。但当前问题描述更偏向于如何避免自动使用JSON格式,而使用multipart格式。 根据引用[1]和[3]: - application/x-www-form-urlencoded:类似GET的编码,数据放在请求体中。 - multipart/form-data:用于大数据传输,有boundary分割。 - application/json:将数据序列化为JSON字符串。 用户希望避免自动使用JSON格式,而是使用multipart格式,并且要求自动生成boundary。 解决方案的关键在于: 1. 不要手动设置Content-Type,让HTTP库自动设置。 2. 使用正确的请求方式(如使用FormData对象)来发送multipart请求。 接下来,我们根据不同场景提供解决方案: 场景一:在浏览器中使用JavaScript(如uni-app的H5平台)发送multipart/form-data请求 - 使用FormData对象,这样浏览器会自动设置Content-Type为multipart/form-data,并生成boundary。 - 不要手动设置Content-Type头部。 场景二:在uni-app中使用uni.uploadFile - 这个API专门用于文件上传,会自动使用multipart格式,并生成boundary。 - 按照之前的方法,不要在header中设置Content-Type。 场景三:在普通JavaScript中发送multipart请求(非文件上传,但有表单字段) - 同样使用FormData对象。 场景四:在Node.js环境中发送multipart请求 - 可以使用form-data库来构建请求。 下面给出具体代码示例: 一、浏览器环境(包括uni-app的H5)发送multipart/form-data请求(非文件上传,只是表单数据) ```javascript // 创建FormData对象 var formData = new FormData(); formData.append(&#39;username&#39;, &#39;John&#39;); formData.append(&#39;age&#39;, 30); // 使用fetch发送请求 fetch(&#39;https://example.com/api&#39;, { method: &#39;POST&#39;, body: formData, // 注意:不要设置Content-Type头,让浏览器自动设置 headers: { // 可以设置其他头,比如Authorization &#39;Authorization&#39;: &#39;Bearer token&#39; } }) .then(response =&gt; response.json()) .then(data =&gt; console.log(data)); ``` 二、uni-app中使用uni.uploadFile(用于文件上传,同时可以传表单数据) ```javascript uni.chooseImage({ success: (res) =&gt; { const tempFilePaths = res.tempFilePaths; uni.uploadFile({ url: &#39;https://example.com/upload&#39;, filePath: tempFilePaths[0], name: &#39;file&#39;, formData: { &#39;username&#39;: &#39;John&#39;, &#39;age&#39;: 30 }, header: { &#39;Authorization&#39;: &#39;Bearer token&#39; // 只设置需要的头,不要设置Content-Type }, success: (uploadRes) =&gt; { console.log(uploadRes.data); } }); } }); ``` 三、Node.js环境(使用form-data库) 首先安装form-data库: ```bash npm install form-data ``` 示例代码: ```javascript const FormData = require(&#39;form-data&#39;); const fs = require(&#39;fs&#39;); const http = require(&#39;http&#39;); const form = new FormData(); form.append(&#39;username&#39;, &#39;John&#39;); form.append(&#39;age&#39;, 30); form.append(&#39;file&#39;, fs.createReadStream(&#39;/path/to/file&#39;)); const request = http.request({ host: &#39;example.com&#39;, path: &#39;/upload&#39;, method: &#39;POST&#39;, headers: { ...form.getHeaders(), // 这里会包含正确的Content-Type和boundary &#39;Authorization&#39;: &#39;Bearer token&#39; } }); form.pipe(request); request.on(&#39;response&#39;, (res) =&gt; { console.log(res.statusCode); }); ``` 四、如果使用axios在浏览器中发送multipart请求 ```javascript const formData = new FormData(); formData.append(&#39;username&#39;, &#39;John&#39;); formData.append(&#39;age&#39;, 30); axios.post(&#39;https://example.com/api&#39;, formData, { headers: { &#39;Authorization&#39;: &#39;Bearer token&#39; // 不要设置Content-Type,axios会自动设置 } }) .then(response =&gt; console.log(response)) .catch(error =&gt; console.error(error)); ``` 总结: - 避免手动设置Content-Type是让HTTP库自动生成boundary的关键。 - 使用支持multipart/form-data的API(如FormData)会自动处理boundary。 - 在uni-app中,上传文件使用uni.uploadFile,不要设置Content-Type头。 如果用户希望发送的是非文件上传的multipart请求(比如只是表单数据),那么使用FormData对象即可。 注意:在uni-app中,如果不需要上传文件,而是发送普通的表单数据(包括非文件字段),则不应该使用uni.uploadFile,而应该使用uni.request,并且同样使用FormData(在H5平台)或者将数据放在formData数中(但注意uni.request默认的Content-Type是application/json,所以需要转换)。 但是,uni.request在非H5平台不支持直接使用FormData对象,所以需要根据不同平台处理: - H5平台:可以使用FormData。 - 非H5平台:需要使用application/x-www-form-urlencoded格式,或者将数据作为普通对象传递(此时会自动使用application/json)。如果后端要求multipart格式,则非H5平台不能直接发送(除非使用插件或原生模块),通常只有上传文件才使用multipart。 因此,在uni-app中发送普通表单数据(非文件): - 如果后端可以接受application/x-www-form-urlencoded或application/json,则可以直接使用uni.request。 - 如果后端必须使用multipart/form-data(即使没有文件),则: H5平台:使用FormData。 非H5平台:需要借助原生插件或使用uni.uploadFile(即使不上传文件,可以传一个空文件?不推荐)或者改变后端接口。 所以,如果用户的问题是如何在uni-app中发送multipart/form-data请求(非文件上传),那么需要分平台处理。但这种情况较少见,因为multipart主要设计用于包含二进制数据的表单。 因此,我们建议: - 如果只是普通表单数据,使用application/x-www-form-urlencoded或application/json。 - 如果包含文件,使用uni.uploadFile(全平台)或使用FormData(H5)。 如果用户的问题是如何避免uni.request自动使用application/json,而改为使用application/x-www-form-urlencoded,则可以设置header: ```javascript uni.request({ url: &#39;https://example.com/api&#39;, method: &#39;POST&#39;, data: { username: &#39;John&#39;, age: 30 }, header: { &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded&#39; }, success: (res) =&gt; { console.log(res.data); } }); ``` 但是,注意:data数需要转换为查询字符串(URL-encoded格式)。uni.request会自动将data对象转换为字符串,但转换方式取决于Content-Type: - 当Content-Type为application/x-www-form-urlencoded时,uni.request会将data对象转换为key=value&amp;key=value的格式。 - 当Content-Type为application/json时,会将data对象转为JSON字符串。 因此,设置正确的Content-Type后,uni.request会自动转换数据格式。 综上所述,用户的问题可能是多方面的,需要根据具体场景提供解决方案。 下面,我们针对用户的问题&ldquo;解决post请求自动变为json格式且不自动生成boundary&rdquo;给出明确的步骤: 目标:发送multipart/form-data请求,并且自动生成boundary。 方案: 1. 如果请求中包含文件,使用uni.uploadFile(uni-app)或FormData(浏览器、H5)并确保不手动设置Content-Type。 2. 如果请求中不包含文件,但需要multipart格式(不常见): - 在浏览器/H5中使用FormData(即使没有文件,也可以添加字段)。 - 在Node.js中使用form-data库。 - 在uni-app的非H5平台,由于uni.request不支持multipart,建议改为使用application/x-www-form-urlencoded或application/json,或者使用第三方插件。 如果用户希望的是避免使用JSON格式,而是使用application/x-www-form-urlencoded,那么只需要在uni.request中设置Content-Type为application/x-www-form-urlencoded。 生成的相关问题: 1. 如何在uni-app中发送application/x-www-form-urlencoded格式请求? 2. 在Node.js中如何发送multipart/form-data请求? 3. 浏览器中发送FormDataJSON格式请求有何区别? 4. 如何在后端(如Spring Boot)同时处理multipart请求JSON请求? 5. 为什么后端要求使用multipart/form-data格式? 请根据用户的具体情况选择解决方案。 &lt;/think&gt; # 解决 POST 请求自动转为 JSON 格式且不生成 boundary 的问题 在 POST 请求中正确处理数据格式是关键问题,我将为您提供完整解决方案。核心问题在于 **Content-Type 设置不当导致请求格式与后端预期不匹配**。 ## 问题分析 根据您的描述,主要存在两个问题: 1. 请求**自动转为 JSON 格式**(application/json) 2. 使用 multipart/form-data 时**未自动生成 boundary** 引用说明: &gt; multipart/form-data 用于传输大数据; 有 boundary 进行数据分割[^1] ## 解决方案 ### 方案一:强制使用 multipart/form-data 格式(推荐) ```javascript // 使用 FormData 对象确保正确生成 boundary const formData = new FormData(); formData.append(&#39;file&#39;, fileInput.files[0]); // 文件字段 formData.append(&#39;username&#39;, &#39;JohnDoe&#39;); // 普通字段 // 使用 fetch API 发送请求 fetch(&#39;/api/upload&#39;, { method: &#39;POST&#39;, body: formData, headers: { // 不要手动设置 Content-Type,浏览器会自动生成 boundary 的格式 &#39;Authorization&#39;: &#39;Bearer your_token_here&#39; } }) .then(response =&gt; response.json()) .then(data =&gt; console.log(data)) .catch(error =&gt; console.error(&#39;Error:&#39;, error)); ``` ### 方案二:明确指定 Content-Type(手动设置 boundary) ```javascript // 生成唯一 boundary const boundary = &#39;----WebKitFormBoundary&#39; + Math.random().toString(36).substring(2); const contentType = `multipart/form-data; boundary=${boundary}`; // 手动构建 multipart 请求体 let body = `--${boundary}\r\n`; body += &#39;Content-Disposition: form-data; name=&quot;username&quot;\r\n\r\n&#39;; body += &#39;JohnDoe\r\n&#39;; body += `--${boundary}\r\n`; body += &#39;Content-Disposition: form-data; name=&quot;file&quot;; filename=&quot;image.jpg&quot;\r\n&#39;; body += &#39;Content-Type: image/jpeg\r\n\r\n&#39;; body += fileBinaryData + &#39;\r\n&#39;; body += `--${boundary}--`; fetch(&#39;/api/upload&#39;, { method: &#39;POST&#39;, body: body, headers: { &#39;Content-Type&#39;: contentType, &#39;Authorization&#39;: &#39;Bearer your_token_here&#39; } }); ``` ## 后端处理要点(Spring Boot 示例) ```java @PostMapping(value = &quot;/upload&quot;, consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity&lt;String&gt; handleUpload( @RequestPart(&quot;file&quot;) MultipartFile file, @RequestParam(&quot;username&quot;) String username, @RequestHeader(&quot;Authorization&quot;) String token) { // 验证 token(移除 Bearer 前缀) String jwt = token.replace(&quot;Bearer &quot;, &quot;&quot;); if(!jwtValidator.validate(jwt)) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } // 处理文件上传 try { file.transferTo(new File(&quot;/uploads/&quot; + file.getOriginalFilename())); return ResponseEntity.ok(&quot;Upload successful for user: &quot; + username); } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(&quot;Upload failed&quot;); } } ``` ## 关键注意事项 1. **Content-Type 自动生成原则**: - 使用 `FormData` API 时,浏览器会自动设置: ``` Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123 ``` - 手动设置任何 `Content-Type` 会覆盖此行为 2. **请求格式对比表**: | 格式 | 适用场景 | 自动 boundary | Content-Type 设置 | |--------------------------|--------------------------|--------------|-------------------| | `application/json` | 结构化数据 | 不适用 | 需要手动设置 | | `multipart/form-data` | 文件/混合数据 | 自动生成 | 不应手动设置 | | `x-www-form-urlencoded` | 简单键值对 | 不适用 | 需要手动设置 | 3. **常见错误排查**: - ✘ 错误:手动设置 `&#39;Content-Type&#39;: &#39;multipart/form-data&#39;` - ✔ 正确:使用 `FormData` 对象,不设置 Content-Type - ✘ 错误:将文件数据作为 JSON 发送 - ✔ 正确:使用 `formData.append()` 添加文件 &gt; RESTful API 接口最常用的数据格式是 application/json,但当涉及文件上传时,multipart/form-data 是更好的选择[^3] ## 不同框架的解决方案 ### Axios 实现 ```javascript import axios from &#39;axios&#39;; const formData = new FormData(); formData.append(&#39;avatar&#39;, file); axios.post(&#39;/api/upload&#39;, formData, { headers: { &#39;Authorization&#39;: `Bearer ${token}`, // 不要设置 Content-Type! } }) ``` ### jQuery 实现 ```javascript const formData = new FormData(); formData.append(&#39;document&#39;, $(&#39;#fileInput&#39;)[0].files[0]); $.ajax({ url: &#39;/api/upload&#39;, type: &#39;POST&#39;, data: formData, processData: false, // 禁用 jQuery 自动转换 contentType: false, // 禁用 jQuery 自动设置 Content-Type headers: {&#39;Authorization&#39;: &#39;Bearer token&#39;}, success: function(response) { console.log(response); } }); ``` ## 总结 解决 POST 请求格式问题的核心要点: 1. 文件上传必须使用 **FormData 对象** 2. **不要手动设置** Content-Type 头部 3. 确保后端接受 `multipart/form-data` 格式 4. 使用框架时禁用自动 Content-Type 设置(如 jQuery 的 `contentType: false`) 这种方法能确保浏览器自动生成正确的 boundary 分隔符,同时避免请求被转为 JSON 格式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值