返回JObject时出现Stack overflow问题排查求助
Azure函数返回JObject触发栈溢出(仅Accept头为application/vnd.api+json时)
问题复现
以下Azure HTTP触发器代码,当请求头Accept: application/vnd.api+json时会触发栈溢出,终端反复输出序列化相关的循环调用栈;移除该头则正常运行:
[FunctionName("HttpTrigger1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { var array = JObject.FromObject(new {dd=1,ddd=2}); var errorresult = new ObjectResult(array); return errorresult; }
循环调用栈片段:
CollectionDataContractAttribute ByRef) at System.Runtime.Serialization.DataContract.GetNonDCTypeStableName(System.Type) at System.Runtime.Serialization.DataContract.GetStableName(System.Type, Boolean ByRef) at System.Runtime.Serialization.DataContract.GetCollectionStableName(System.Type, System.Type, System.Runtime.Serialization.CollectionDataContractAttribute ByRef) ...(循环重复)
原因分析
当请求指定Accept: application/vnd.api+json时,ASP.NET Core默认会选用DataContractSerializer处理响应序列化,但Newtonsoft.Json的JObject类型内部结构与DataContractSerializer的处理逻辑不兼容,导致序列化过程中出现无限递归调用,最终引发栈溢出。而默认的application/json头会使用Newtonsoft.Json或System.Text.Json格式化器,能正确处理JObject。
解决方案
方案1:改用JsonResult替代ObjectResult
直接使用JsonResult指定序列化逻辑,避免触发DataContractSerializer:
[FunctionName("HttpTrigger1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { var array = JObject.FromObject(new {dd=1,ddd=2}); // 直接返回JsonResult,默认用Newtonsoft.Json处理 return new JsonResult(array); }
如果需要指定application/vnd.api+json作为响应ContentType:
return new JsonResult(array) { ContentType = "application/vnd.api+json" };
方案2:配置格式化器,让application/vnd.api+json使用Newtonsoft.Json
在Azure函数的配置类(隔离进程模式用Program.cs,In-Process模式用Startup.cs)中,为application/vnd.api+json添加NewtonsoftJsonOutputFormatter:
// 隔离进程模式Program.cs示例 var host = new HostBuilder() .ConfigureFunctionsWebApplication() .ConfigureServices(services => { services.AddMvcCore(options => { var mediaType = MediaTypeHeaderValue.Parse("application/vnd.api+json"); var newtonsoftFormatter = new NewtonsoftJsonOutputFormatter( new JsonSerializerSettings(), ArrayPool<char>.Shared, options); newtonsoftFormatter.SupportedMediaTypes.Add(mediaType); options.OutputFormatters.Insert(0, newtonsoftFormatter); }); }) .Build(); host.Run();
方案3:避免直接返回JObject
将JObject转换为匿名对象或强类型POCO,让DataContractSerializer可以正确处理:
[FunctionName("HttpTrigger1")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log) { // 直接用匿名对象,无需转JObject var data = new {dd=1,ddd=2}; return new ObjectResult(data); }
内容的提问来源于stack exchange,提问作者tulipe
相关产品推荐
相关产品推荐

