You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产环境下ASP.NET Core MVC返回409时无法读取自定义错误消息

ASP.NET Core MVC生产环境4xx错误响应异常问题解答

问题背景

搭建ASP.NET Core MVC服务器实现错误处理,本地环境返回4xx状态码时,客户端能正常读取自定义JSON错误信息;但部署到生产环境后,客户端调用response.json()时出现SyntaxError: Unexpected token T in JSON at position 0错误,无法读取自定义错误消息,而200成功响应则能正常读取展示。

控制器代码

[HttpPost]
public JsonResult SaveRecord([FromBody]NewsLanguage newLanguage)
{
    try
    {
        _context.NewsLanguages.Add(newLanguage);
        _context.SaveChanges();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Response.StatusCode = 409;                             
        string errMsg = ex.Message;
        if (ex.InnerException != null)
            errMsg = ex.InnerException.Message;                
        return Json(new { status = "Error", message = errMsg });                
    }
    Response.StatusCode = 200;
    return Json(new { status = "success", 
        message = "New News Language Saved Successfully!" });
                
}

前端fetch请求代码

try {
    const response = await submitForm("/saverecord", newsLanguage, "POST");
    console.log(response);
    if (response.ok)
        handleResponse(response, newsLanguage);
    else {
        const err = await response.json();
        throw new Error(err.message || err.statusText)
    }
} catch (err) {
    console.log(err);
    handleErrorResponse(err, newsLanguage);            
} 

function submitForm(route, newsLanguage, method) {
    const requestOptions =
    {
        method: method,
        headers:
        {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(newsLanguage)
    };
    return fetch(parurl + route, requestOptions);
}

async function handleResponse(response, newsLanguage, method) {    
    const data = await response.json();
    console.log(response, data)
    if (data.status === "success") {
        document.getElementById("ModalFormClose").click();
        toastr.success(data.message, "PERLEWEB DATABASE INTERFACE");

        if (method != "DELETE") {
            let table = $('#example').DataTable();
            table.row.add({ "id": newsLanguage.Id, 
                "languageName": newsLanguage.LanguageName }).draw();
        } else {
            var table = $('#example').DataTable();
            table.row($(this).parents('tr')).remove().draw();
        }
    } else {
        toastr.error(response.responseJSON.message, "ERROR!")
    }    
}

function handleErrorResponse(errorMsg) {
    toastr.error(errorMsg, "ERROR!")
}

核心问题解答

1. 失败请求的错误消息去哪了?

你的自定义错误消息被生产环境服务器(如IIS)拦截,替换成了服务器默认的HTML错误页面。报错中的Unexpected token T就是因为响应内容是HTML(比如IIS默认409错误页开头为"Too..."),而非你返回的JSON数据。

2. 是否有办法显示该错误消息,还是只能返回HTTP响应状态码?

可以显示自定义错误消息,需要同时配置ASP.NET Core项目和生产服务器,确保4xx错误的自定义响应不会被拦截替换。

3. 为什么成功响应可以正常读取,错误响应却不行?

  • 200成功响应属于正常状态码,生产服务器默认不会干预这类响应,你的JSON数据能直接传递到客户端。
  • 4xx属于客户端错误状态码,生产服务器(如IIS)默认会自动替换这类响应为自身的错误页面,覆盖了你返回的自定义JSON。

4. 本地环境与生产环境的差异是否由服务器配置导致?

是。本地开发环境使用的Kestrel服务器默认不会拦截替换错误响应;而生产环境通常用IIS作为反向代理,IIS默认会处理4xx/5xx错误并返回自身页面,同时ASP.NET Core的生产环境配置也可能存在错误处理中间件的差异。


解决方案

1. 修改ASP.NET Core控制器代码

使用框架提供的IActionResult返回类型和对应状态码方法,替代直接设置Response.StatusCode,确保响应被正确处理:

[HttpPost]
public IActionResult SaveRecord([FromBody]NewsLanguage newLanguage)
{
    try
    {
        _context.NewsLanguages.Add(newLanguage);
        _context.SaveChanges();
        return Ok(new { status = "success", message = "New News Language Saved Successfully!" });
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        string errMsg = ex.Message;
        if (ex.InnerException != null)
            errMsg = ex.InnerException.Message;
        // 使用Conflict方法返回409状态码和自定义JSON
        return Conflict(new { status = "Error", message = errMsg });
    }
}

2. 配置ASP.NET Core错误处理中间件

在Program.cs中添加配置,禁用默认的状态码页面替换,确保自定义响应能正常输出:

// 针对特定接口禁用状态码页面替换
app.UseWhen(context => context.Request.Path.StartsWithSegments("/saverecord"), appBuilder =>
{
    appBuilder.UseStatusCodePages(context =>
    {
        return Task.CompletedTask;
    });
});

// 全局异常处理(可选,确保未捕获异常返回JSON)
app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = StatusCodes.Status500InternalServerError;
        context.Response.ContentType = "application/json";
        await context.Response.WriteAsJsonAsync(new { status = "Error", message = "服务器内部错误" });
    });
});

3. 配置IIS(若部署在IIS上)

在项目的web.config中添加配置,让IIS保留ASP.NET Core返回的原始响应,不替换为自身错误页:

<system.webServer>
  <httpErrors errorMode="DetailedLocalOnly" existingResponse="PassThrough" />
</system.webServer>

4. 前端代码容错处理

增加JSON解析失败的 fallback,避免因响应非JSON导致的报错:

else {
    try {
        const err = await response.json();
        throw new Error(err.message || err.statusText);
    } catch (parseErr) {
        // 解析JSON失败时,读取响应文本作为错误信息
        const errText = await response.text();
        throw new Error(errText || `请求失败:${response.status}`);
    }
}

内容的提问来源于stack exchange,提问作者d0rf47

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 00:36:21