API返回JSON被外层'd'字段包裹问题排查求助
问题描述
处理API请求时,将DataTable序列化为JSON返回,但响应被外层{'d': '...'}结构包裹,且内部JSON字符串存在转义。
API输入示例
{ "region_id": "ID-10", "document_number": "10-80/81-BIN-00005", "industry_no": "10-CNO-0001", "posting_date": "14-07-2080", "customer_number": "10-CNO-0001", "payment_for": [ {"BillType": "पानी महशुल"} ] }
当前API响应示例
{ "d": "[{\"CustomerNo\":\"10-CNO-0001\",\"PostingDate\":\"2023-10-31T00:00:00\",\"DocumentNo\":\"10-80/81-BIN-00005\",\"BillType\":\"5\",\"Description\":\"पानी महशुल\",\"Quantity\":0.00000,\"Rate\":0.00000,\"Amount\":1000.00,\"RegionID\":\"ID-10\",\"ExpenseID\":\"0\",\"ActivityID\":\"0\",\"SubActivityID\":\"0\",\"Dimension5ID\":\"\",\"FineAmount\":0.00,\"DiscountAmount\":-40.00,\"IsPaid\":false,\"priority\":\"2\",\"billType\":\"5\"}]" }
处理代码
[WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] [AllowAnonymous] public string InitialFetch(string region_id, string document_number, string industry_no, string posting_date, string customer_number, List<PaymentForItem> payment_for) { try { // Create a dictionary to represent the processed data var extractedData = new Dictionary<string, object> { { "region_id", region_id }, { "document_number", document_number }, { "industry_no", industry_no }, { "posting_date", posting_date }, { "customer_number", customer_number }, { "payment_for", payment_for.Select(item => new Dictionary<string, object> { { "BillType", item.BillType } }).ToList() } }; // Call the original GetReceivableByBillTypeFromLaravel method a datatable is extracted DataTable receiptData = GetReceivableByBillTypeFromLaravel(extractedData); // Serialize the response to JSON string jsonResponse = JsonConvert.SerializeObject(receiptData); return jsonResponse; } catch (Exception ex) { // Handle any exceptions and return an error response return JsonConvert.SerializeObject(new { error = "Error: " + ex.Message }); } }
问题原因
- WebMethod默认包装机制:ASP.NET的
WebMethod配合ScriptMethod使用时,会自动将返回值包裹在d属性中,这是ASP.NET AJAX的默认行为,用于兼容早期AJAX请求的安全和跨域处理逻辑。 - 双重序列化问题:你在代码中手动用
JsonConvert.SerializeObject把DataTable序列化为JSON字符串,WebMethod会将这个字符串当作普通字符串再次进行JSON序列化,导致最终响应里d的值是转义后的JSON字符串,而非直接的JSON对象/数组。
解决方案
方案1:直接返回DataTable(推荐)
修改方法返回类型为DataTable,移除手动序列化步骤,让WebMethod自动处理序列化逻辑:
[WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] [AllowAnonymous] public DataTable InitialFetch(string region_id, string document_number, string industry_no, string posting_date, string customer_number, List<PaymentForItem> payment_for) { try { var extractedData = new Dictionary<string, object> { { "region_id", region_id }, { "document_number", document_number }, { "industry_no", industry_no }, { "posting_date", posting_date }, { "customer_number", customer_number }, { "payment_for", payment_for.Select(item => new Dictionary<string, object> { { "BillType", item.BillType } }).ToList() } }; DataTable receiptData = GetReceivableByBillTypeFromLaravel(extractedData); return receiptData; } catch (Exception ex) { throw new Exception("Error: " + ex.Message); } }
此时WebMethod会自动将DataTable序列化为JSON数组并包裹在d中,内部不会出现转义问题。
方案2:禁用全局响应包装(谨慎使用)
如果需要完全移除外层d结构,可以修改Web.config配置,禁用ASP.NET AJAX的自动包装:
<configuration> <system.web.extensions> <scripting> <webServices> <jsonSerialization enableJsonp="true" maxJsonLength="50000000" /> <authenticationService enabled="true" requireSSL="false"/> <webServices> <jsonSerialization serializeAsJson="true"/> </webServices> </webServices> </scripting> </system.web.extensions> </configuration>
注意:该配置会影响所有WebMethod的响应格式,需评估后使用。
方案3:返回自定义对象/匿名对象
若需要自定义响应结构(比如统一错误格式),可以返回匿名对象或强类型对象,避免手动序列化:
[WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] [AllowAnonymous] public object InitialFetch(string region_id, string document_number, string industry_no, string posting_date, string customer_number, List<PaymentForItem> payment_for) { try { var extractedData = new Dictionary<string, object> { { "region_id", region_id }, { "document_number", document_number }, { "industry_no", industry_no }, { "posting_date", posting_date }, { "customer_number", customer_number }, { "payment_for", payment_for.Select(item => new Dictionary<string, object> { { "BillType", item.BillType } }).ToList() } }; DataTable receiptData = GetReceivableByBillTypeFromLaravel(extractedData); // 将DataTable转换为强类型对象或匿名对象,优化序列化效果 var result = receiptData.AsEnumerable().Select(row => new { CustomerNo = row["CustomerNo"], PostingDate = row["PostingDate"], DocumentNo = row["DocumentNo"], BillType = row["BillType"], Description = row["Description"], Amount = row["Amount"] // 其他字段按需添加 }).ToList(); return result; } catch (Exception ex) { return new { error = "Error: " + ex.Message }; } }
这种方式既避免了双重序列化,又能灵活控制响应结构,WebMethod会自动完成序列化。
内容的提问来源于stack exchange,提问作者Roasted 101
相关产品推荐
相关产品推荐

