如何在Web API请求的JSON字符串中添加反斜杠?
我编写了一段JavaScript代码,用于获取表单数据并转换为对象,序列化后发送Web API请求。现在需要给生成的JSON字符串添加反斜杠,示例如下:
- 原序列化字符串:
{"application_name":"test1","application_name_Id":"1225848d-5941-4fac-bdff-7799b53d6fd0"}
- 目标字符串(带转义):
{\"application_name\":\"test1\",\"application_name_Id\":\"1225848d-5941-4fac-bdff-7799b53d6fd0\"}
前端JavaScript代码
function PostForm() { const form = document.querySelector('#myForm'); const data = new URLSearchParams(new FormData(form).entries()); const obj = Object.fromEntries(data); for (let key in obj) { if (!isNaN(obj[key])) { obj[key] = Number(obj[key]); } } const stringifyObj = JSON.stringify(obj); console.log(stringifyObj) $.ajax({ url: 'https://localhost:7273/WeatherForecast', type: 'POST', data: stringifyObj, dataType: 'json', contentType: "application/json;charset=utf-8", success: function (response) { debugger console.log(response); }, error: function (XMLHttpRequest, textStatus, errorThrown) { debugger console.log(XMLHttpRequest.responseText) } }); }
后端C# Web API代码
当前使用dynamic类型可以正常获取值:
[HttpPost] public void Post([FromBody] dynamic jsonString) { // 代码已省略 }
但将参数类型改为string后无法正常工作,此时jsonString的值为:
"{"application_name":"test1","application_name_Id":"1225848d-5941-4fac-bdff-7799b53d6fd0"}"
而非预期的带转义的字符串:
"{\"application_name\":\"test1\",\"application_name_Id\":\"1225848d-5941-4fac-bdff-7799b53d6fd0\"}"
另外,若将ajax的data改为直接传obj,会收到400错误,错误信息如下:
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "errors": { "$": ["'a' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0."] }, "status": 400, "title": "One or more validation errors occurred.", "traceId": "00-b01059fa2d870ff1f3e4309f6291cc9e-d02e73b547a874f5-00" }
1. 问题根源
当后端用[FromBody] string接收时,ASP.NET Core会将请求体的原始JSON内容直接反序列化为string。但前端发送的是一个JSON对象(比如{"application_name":"test1"}),框架解析时会把整个对象的结构当成string的内容,导致引号没有转义——因为这些引号是JSON对象的语法部分,并非字符串的转义符。
2. 解决方法
方法一:前端二次序列化JSON
要让后端拿到带转义的字符串,只需对已经序列化好的JSON字符串再做一次序列化:
// 替换原来的JSON.stringify(obj)为二次序列化 const stringifyObj = JSON.stringify(JSON.stringify(obj));
这样发送到后端的内容就是一个包含转义引号的字符串,[FromBody] string参数就能接收到预期的"{\"application_name\":\"test1\",...}"。
方法二:后端定义实体类接收(更推荐)
相比让前端做二次序列化,后端定义对应的数据实体类是更规范、类型安全的做法:
// 定义与前端数据结构匹配的实体类 public class ApplicationRequest { public string application_name { get; set; } public string application_name_Id { get; set; } // 如果有数字类型字段,直接定义为int/long等对应类型 } // 修改接口参数为实体类 [HttpPost] public void Post([FromBody] ApplicationRequest request) { // 直接使用request.application_name、request.application_name_Id即可 }
前端保持原有的JSON.stringify(obj)发送,ASP.NET Core会自动将JSON请求体解析到实体类中,无需手动处理字符串转义。
3. 为什么传obj会报400错误?
当直接传obj给ajax的data参数时,jQuery默认会把对象序列化为application/x-www-form-urlencoded格式(类似application_name=test1&application_name_Id=xxx),但你设置了contentType: "application/json;charset=utf-8",后端会尝试把表单格式的内容当成JSON解析,自然会出现语法错误。如果要传对象,要么让jQuery自动处理contentType(去掉手动设置的contentType),要么还是用JSON.stringify(obj)发送标准JSON字符串。
内容的提问来源于stack exchange,提问作者Steve

