如何在hx-post中发送对象数据?JSON.stringify数组加引号问题
HTMX+Spring Boot JSON数组反序列化问题解决
问题背景
后端Spring Boot接口接收POST请求的DTO定义如下:
public record FileMetadataDTO(Integer availabilityTime, FileDTO[] files) {} public record FileDTO(String name, String extension, Integer sizeMB) {}
前端用HTMX发送请求的按钮代码:
<button id="upload-button" hx-post="http://localhost:8080/api/v1/upload/metadata" hx-headers='{"Content-Type": "application/json"}' hx-ext="json-enc" hx-vals='js:{"availabilityTime": 1, "files": getFilesDTO()}' style="display: none;">Upload</button> <label for="upload-button" style="border: 1px solid #ccc; padding: 6px 12px; cursor: pointer;">Upload files</label>
原本的getFilesDTO()函数会对数组做JSON.stringify处理:
function getFilesDTO() { let filesDTO = []; for (let i = 0; i < tuckedFiles.length; i++) { filesDTO.push({ name: tuckedFiles[i].name, extension: tuckedFiles[i].name.split('.').pop(), sizeMB: tuckedFiles[i].size / 1024 / 1024 }); } return JSON.stringify(filesDTO); }
这导致请求载荷格式错误——files字段变成带引号的字符串,后端无法反序列化:
{"availabilityTime":"1","files":"[{\"name\":\"a.txt\",\"extension\":\"txt\",\"sizeMB\":0.00022220611572265625},{\"name\":\"another_file.txt\",\"extension\":\"txt\",\"sizeMB\":0.000003814697265625}]"}
合法的请求载荷应为:
{"availabilityTime":"1","files":[{"name":"a.txt","extension":"txt","sizeMB":0.00022220611572265625},{"name":"another_file.txt","extension":"txt","sizeMB":0.000003814697265625}]}
原因分析
HTMX的json-enc扩展会自动将hx-vals中返回的JS对象序列化为完整的JSON字符串。如果手动对数组调用JSON.stringify,会触发双重序列化:原生数组先被转成字符串,再被json-enc当作普通字符串处理,最终在请求体里变成带引号的字符串值。
解决方案
修改getFilesDTO()函数,去掉JSON.stringify,直接返回原生JS数组对象:
function getFilesDTO() { let filesDTO = []; for (let i = 0; i < tuckedFiles.length; i++) { filesDTO.push({ name: tuckedFiles[i].name, extension: tuckedFiles[i].name.split('.').pop(), sizeMB: tuckedFiles[i].size / 1024 / 1024 }); } // 直接返回JS数组,无需手动序列化 return filesDTO; }
验证结果
修改后,HTMX的json-enc会自动将整个{availabilityTime:1, files: [...]}对象序列化为正确的JSON格式,后端Spring Boot可正常反序列化为FileMetadataDTO对象。
内容的提问来源于stack exchange,提问作者Rawres
相关产品推荐
相关产品推荐

