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

ASP.NET Core中Hot Chocolate返回错误至Angular Apollo Client异常排查

问题描述

在ASP.NET Core中使用Hot Chocolate实现GraphQL接口,当检测到邮箱已存在时抛出GraphQLException,期望Angular端通过Apollo Client捕获并显示错误,但实际控制台仅显示内部服务器错误,无法在前端错误回调中获取到自定义错误信息。

后端Mutation代码:

public async Task<UserType?> CreateUser([UseFluentValidation, UseValidator<RegisterInputTypeValidator>()]RegisterInputType model, [Service]IUserRepository userRepository)
{
    var userExist = await userRepository.GetUserByEmail(model.Email);

    if (userExist != null)
    {
        throw new GraphQLException(new List<Error>()
        {
            new Error("Email already exists"),
        });
    }

    AppUser user = new AppUser
    {
        Email = model.Email,
        FullName = model.FullName,
        UserName = model.Email,
        AvatarUrl = model.AvatarUrl,
        PhoneNumber = ""
    };

    var r = await userRepository.CreateUserAsync(user, model.Password);

    if (r.Succeeded == false)
    {
        var err = r.Errors.Select(e => new Error(e.Description)).ToList();
        throw new GraphQLException(err);
    }

    return new UserType
    {
        Email = user.Email,
        FullName = user.FullName,
        AvatarUrl = user.AvatarUrl,
        PhoneNumber = user.PhoneNumber!,
        FriendIds = user.FriendIds,
        GroupIds = user.GroupIds
    };
}

Angular前端代码:

this.apollo
    .mutate({
        mutation: CREATE_USER,
        variables: {
            email: this.registerForm.controls['email'].value,
            fullName: this.registerForm.controls['fullName'].value,
            password: this.registerForm.controls['password'].value,
            reEnterPassword: this.registerForm.controls['reEnterPassword'].value,
            avatarUrl: '',      
        },
    })
    .subscribe({
        next: (result) => {
            console.log(result);
        },
        error: (err) => {
            // 无法捕获自定义错误
            console.log(err.message);
        }
    });
解决方案

1. 配置Hot Chocolate确保错误正确返回(后端)

默认情况下Hot Chocolate会将GraphQLException序列化为GraphQL规范的错误格式,但如果ASP.NET Core的全局错误处理中间件(如UseExceptionHandler)拦截了请求,会返回500状态码而非GraphQL的错误响应。可通过以下方式修复:

方法一:调整中间件顺序

在Program.cs中先注册GraphQL中间件,再注册全局错误处理中间件,避免GraphQL请求被全局错误处理拦截:

var app = builder.Build();

// 优先注册GraphQL中间件
app.MapGraphQL();

// 再注册全局错误处理等其他中间件
app.UseExceptionHandler("/error");
// 其他中间件配置...

方法二:显式配置Hot Chocolate错误处理

注册GraphQL服务时,设置异常处理器确保GraphQLException返回200状态码,保留错误信息:

builder.Services.AddGraphQLServer()
    .AddQueryType<Query>()
    .AddMutationType<Mutation>()
    // 其他类型、验证器等配置
    .SetExceptionHandler(async context =>
    {
        if (context.Exception is GraphQLException)
        {
            // 确保GraphQL错误返回200状态码,而非500
            context.Response.StatusCode = StatusCodes.Status200OK;
        }
        await Task.CompletedTask;
    });

可选:为错误添加自定义Code

抛出异常时为错误对象添加Code属性,方便前端区分错误类型:

if (userExist != null)
{
    throw new GraphQLException(new List<Error>()
    {
        new Error("邮箱已存在") { Code = "EMAIL_DUPLICATE" },
    });
}

2. 调整Apollo Client错误处理逻辑(前端)

Apollo Client会将GraphQL规范的错误放在graphQLErrors数组中,而非直接在err.message里。修改错误回调逻辑,读取graphQLErrors获取自定义错误信息:

this.apollo
    .mutate({
        mutation: CREATE_USER,
        variables: {
            email: this.registerForm.controls['email'].value,
            fullName: this.registerForm.controls['fullName'].value,
            password: this.registerForm.controls['password'].value,
            reEnterPassword: this.registerForm.controls['reEnterPassword'].value,
            avatarUrl: '',      
        },
    })
    .subscribe({
        next: (result) => {
            console.log(result);
        },
        error: (err) => {
            // 处理GraphQL业务错误
            if (err.graphQLErrors && err.graphQLErrors.length > 0) {
                const errorMessages = err.graphQLErrors.map(e => e.message).join(';');
                console.log(errorMessages);
                // 可将错误信息绑定到页面显示
                // this.errorMsg = errorMessages;
            } 
            // 处理网络层面错误
            else if (err.networkError) {
                console.log('网络请求失败:', err.networkError.message);
            }
        }
    });

验证步骤

  1. 重启后端服务确保配置生效
  2. 提交重复邮箱的注册请求,查看浏览器网络面板:GraphQL响应状态码应为200,响应体包含errors数组
  3. 前端控制台应打印出自定义错误信息(如"邮箱已存在")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:47:02