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

Fetch API封装函数返回数据undefined问题求助

解决Fetch封装函数返回undefined的问题

问题背景

封装了Fetch API的crudHandler函数,用于调用API获取当前登录用户信息供多视图使用。API调用已成功获取数据,但在视图中访问时返回undefined。

问题代码

主封装函数

function crudHandler(options: IFetchAPIOptions) {
    const url = options.url || '';
    const contentType = options.contentType || ContentTypes["application/json"];
    const failMessage = options.failMessage || '';
    const successMessage = options.successMessage || '';
    const mode = options.mode || 'cors';
    const redirect = options.redirect || 'follow';
    const body = options.body || null;
    const method = options.method || "GET";
    const success = options.success || null
    const error = options.error || null
    let serverSideMessaging = options.serverSideMessaging || false;

    function errorHandler(statusCode: number, errorMessage: string): void {
        if (failMessage != null) {
            matchBookerAlert('danger', failMessage);
            serverSideMessaging = false;
        }
        if (serverSideMessaging == true) {
            matchBookerAlert('danger', statusCode + " - " + errorMessage);
        }
    }
    function messageHandler(data: IMessageHandler): void {
        if (successMessage.length > 0) {
            matchBookerAlert('success', successMessage);
            serverSideMessaging = false;
        }

        if (serverSideMessaging == true && 'SuccessMessage' in data) {
            matchBookerAlert('success', data.successMessage);
        }
        if (serverSideMessaging == true && 'FailMessage' in data) {
            matchBookerAlert('danger', data.failMessage);
        }
    }

    await fetch(url, {
        method: method,
        headers: {
            "content-type": contentType
        },
        mode: mode as RequestMode,
        redirect: redirect as RequestRedirect,
        body: body,
    })
        .then(response => {
            if (!response.ok) {
                if (error !== null) {
                    error(); // need to know what to pass
                }
                errorHandler(response.status, response.statusText);
            }
            return response.json();  
        })
        .then(data => {
            if (success !== null) {
                success(data);
            }
            messageHandler(data);
        })
        .catch(error => {
        console.error(error);
    });
}

获取用户信息的辅助函数

function getCurrentUser(){
    var data = crudHandler({
        url: "/api/AccountApi/GetCurrentUserInfo",
        contentType: ContentTypes["application/json"],
    });
    return data;// I know this is wrong but I don't know how to return the data.
}

调用代码

var currentUser = getCurrentUser();
console.log(currentUser);

后端API方法

[HttpGet]
[Authorize]
[Route("GetCurrentUserInfo")]
public ActionResult GetCurrentUserInfo()
{
    var user = UserManager.FindByIdAsync(CurrentUserId).Result;

    if (user == null)
        return NotFound("User not found");

    CurrentUserInfo currentUserInfo = new CurrentUserInfo()
    {
        FirstName = user.FirstName,
        LastName = user.Lastname,
        Email = user.Email,
        IsAdmin = IsAdmin,
        IsBooker = IsBooker,
        IsOwner = IsOwner,
    };

    return Ok(currentUserInfo);
}

问题原因

  1. 异步处理缺失:crudHandler使用了await但未标记为async函数,也没有返回异步操作的结果(Promise),导致调用该函数直接得到undefined。
  2. 同步调用异步函数:getCurrentUser直接同步调用crudHandler,没有等待异步操作完成,因此返回的不是API数据而是undefined。

修复方案

1. 修改crudHandler为异步函数并返回数据

将函数标记为async,使用try/catch处理异步错误,最终返回API响应数据:

async function crudHandler(options: IFetchAPIOptions): Promise<any> {
    const url = options.url || '';
    const contentType = options.contentType || ContentTypes["application/json"];
    const failMessage = options.failMessage || '';
    const successMessage = options.successMessage || '';
    const mode = options.mode || 'cors';
    const redirect = options.redirect || 'follow';
    const body = options.body || null;
    const method = options.method || "GET";
    const success = options.success || null
    const error = options.error || null
    let serverSideMessaging = options.serverSideMessaging || false;

    function errorHandler(statusCode: number, errorMessage: string): void {
        if (failMessage != null) {
            matchBookerAlert('danger', failMessage);
            serverSideMessaging = false;
        }
        if (serverSideMessaging == true) {
            matchBookerAlert('danger', statusCode + " - " + errorMessage);
        }
    }
    function messageHandler(data: IMessageHandler): void {
        if (successMessage.length > 0) {
            matchBookerAlert('success', successMessage);
            serverSideMessaging = false;
        }

        if (serverSideMessaging == true && 'SuccessMessage' in data) {
            matchBookerAlert('success', data.successMessage);
        }
        if (serverSideMessaging == true && 'FailMessage' in data) {
            matchBookerAlert('danger', data.failMessage);
        }
    }

    try {
        const response = await fetch(url, {
            method: method,
            headers: {
                "content-type": contentType
            },
            mode: mode as RequestMode,
            redirect: redirect as RequestRedirect,
            body: body,
        });

        if (!response.ok) {
            error?.(response.status, response.statusText); // 传递错误信息给回调
            errorHandler(response.status, response.statusText);
            throw new Error(`${response.status} - ${response.statusText}`);
        }

        const data = await response.json();
        success?.(data);
        messageHandler(data);
        return data; // 返回API数据
    } catch (err) {
        console.error(err);
        throw err; // 抛出错误让调用方处理
    }
}

2. 修改getCurrentUser为异步函数

使用await等待crudHandler的异步结果:

async function getCurrentUser(): Promise<any> {
    const data = await crudHandler({
        url: "/api/AccountApi/GetCurrentUserInfo",
        contentType: ContentTypes["application/json"],
    });
    return data;
}

3. 正确调用获取用户信息

由于异步函数不能直接同步调用,需使用async/await或.then()处理结果:

// 方式1:在async函数中使用await
async function loadUserInfo() {
    try {
        const currentUser = await getCurrentUser();
        console.log(currentUser);
        // 在这里更新视图逻辑
    } catch (err) {
        console.error('获取用户信息失败:', err);
    }
}

loadUserInfo();

// 方式2:使用.then()链式调用
getCurrentUser()
    .then(currentUser => {
        console.log(currentUser);
        // 更新视图逻辑
    })
    .catch(err => console.error('获取用户信息失败:', err));

额外优化点

  • 为返回数据定义具体的TypeScript接口(比如CurrentUserInfo),替代any类型,提升类型安全性。
  • 错误回调传递具体的错误信息,方便调用方自定义错误处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 15:45:21