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

如何通过React Modal输入内容修改Axios POST请求头

问题描述

我正在开发一个React Web应用,要求每次发起POST请求时弹出模态框(Modal),让用户输入审批令牌(Approval Token),并将该令牌添加到请求头中再发送至服务器。

现有代码如下:

Axios请求代码

axios({ 
 url: '/backend/call',
 method: 'POST'
}) 

Axios请求拦截器代码

axios.interceptors.request.use(function (config) {
    if (config.method === 'POST') {
        ApprovalPopup.useApprovalPopup.showPopup(); // 显示包含文本框和提交按钮的模态框
        const token = --------; // 如何在用户点击提交后,从模态框中获取此处的令牌?
        config.headers.approvalToken =  token;
    }
    return config;
 });

模态框组件代码

export type IApprovalPopup = {
    showPopup: () => void;
};

const ApprovalPopupContext = createContext<IApprovalPopup>({
    showPopup: () => undefined,
});

export default function ApprovalPopupProvider({children}: { children: ReactNode }) {
    const dialogRef = useRef<HTMLDialogElement>(null);
    const [ticketID, setTicketID] = useState('');

    function handleTicketIDEntry(value: string) {
        setTicketID(value);
    }

    function handleSubmit() {
        // 更新状态并发起后端请求
    }

    function showPopup() {
        dialogRef.current?.show()
    }

    return (
        <ApprovalPopupContext.Provider
            value={{
                showPopup
            }}
        >
                <span slot="body">
                    <div className="ticket-entry">
                        <Label> Ticket ID</Label>
                        <TextField onTextFieldChange={(event) => handleTicketIDEntry(event.detail.value)}
                                         label="Ticket-ID"
                                         value={ticketID}>
                        </TextField>
                    </div>
                    <div className="submit-section">
                        <div className="button">
                            <Button className="button" onClick={handleSubmit}>
                                Submit
                            </Button>
                        </div>
                    </div>
                </span>
            {children}
        </ApprovalPopupContext.Provider>
    );
}

ApprovalPopupProvider.useApprovalPopup = () => useContext(ApprovalPopupContext);

核心问题:如何从模态框中获取令牌,并在发送请求前将其添加到请求头中?

*补充说明:我可以让第一次请求失败,同时将config传递给模态框,由模态框添加请求头后发起请求,但这样如何确保响应能返回给实际调用组件?调用组件需要更新本地状态、处理自定义错误等,因此需要Promise得到正确解析。


解决方案

核心思路是让请求拦截器返回Promise,等待用户提交令牌后再resolve修改后的请求配置,既能保证请求流程的等待逻辑,又能维持原请求的Promise链完整性,确保调用组件能正常接收响应或错误。

步骤1:修改模态框上下文,支持回调传递

更新IApprovalPopup类型,让showPopup方法可以接收提交和取消的回调函数,用于传递用户输入的令牌或取消操作:

export type IApprovalPopup = {
    showPopup: (onSubmit: (token: string) => void, onCancel?: () => void) => void;
};

const ApprovalPopupContext = createContext<IApprovalPopup>({
    showPopup: () => undefined,
});

步骤2:更新模态框Provider逻辑

在Provider中保存回调函数,用户提交或取消时触发对应逻辑,同时关闭模态框并清理状态:

export default function ApprovalPopupProvider({children}: { children: ReactNode }) {
    const dialogRef = useRef<HTMLDialogElement>(null);
    const [ticketID, setTicketID] = useState('');
    const [submitCallback, setSubmitCallback] = useState<((token: string) => void) | null>(null);
    const [cancelCallback, setCancelCallback] = useState<(() => void) | null>(null);

    function handleTicketIDEntry(value: string) {
        setTicketID(value);
    }

    function handleSubmit() {
        if (submitCallback && ticketID.trim()) {
            submitCallback(ticketID.trim());
            dialogRef.current?.close();
            resetPopupState();
        }
    }

    function handleCancel() {
        cancelCallback?.();
        dialogRef.current?.close();
        resetPopupState();
    }

    function resetPopupState() {
        setSubmitCallback(null);
        setCancelCallback(null);
        setTicketID('');
    }

    function showPopup(onSubmit: (token: string) => void, onCancel?: () => void) {
        setSubmitCallback(onSubmit);
        setCancelCallback(onCancel || (() => {}));
        dialogRef.current?.showModal(); // 使用showModal确保模态框拦截用户操作
    }

    return (
        <ApprovalPopupContext.Provider
            value={{
                showPopup
            }}
        >
            {/* 补充dialog元素,之前代码遗漏 */}
            <dialog ref={dialogRef}>
                <span slot="body">
                    <div className="ticket-entry">
                        <Label> Ticket ID</Label>
                        <TextField 
                            onTextFieldChange={(event) => handleTicketIDEntry(event.detail.value)}
                            label="Ticket-ID"
                            value={ticketID}
                        />
                    </div>
                    <div className="submit-section">
                        <div className="button">
                            <Button className="button" onClick={handleSubmit}>
                                Submit
                            </Button>
                            <Button className="button" onClick={handleCancel} variant="secondary">
                                Cancel
                            </Button>
                        </div>
                    </div>
                </span>
            </dialog>
            {children}
        </ApprovalPopupContext.Provider>
    );
}

ApprovalPopupProvider.useApprovalPopup = () => useContext(ApprovalPopupContext);

步骤3:修改Axios拦截器,返回等待Promise

拦截POST请求时,返回Promise等待用户输入,提交后注入令牌并继续请求,取消则抛出错误:

axios.interceptors.request.use(function (config) {
    if (config.method?.toLowerCase() === 'post') {
        return new Promise((resolve, reject) => {
            ApprovalPopup.useApprovalPopup.showPopup(
                // 用户提交令牌后的逻辑
                (token) => {
                    config.headers.approvalToken = token;
                    resolve(config);
                },
                // 用户取消后的逻辑
                () => {
                    reject(new Error('用户取消了令牌输入'));
                }
            );
        });
    }
    return config;
});

步骤4:调用组件正常处理结果

原请求的Promise链不受影响,调用组件可正常处理响应和错误:

axios({ 
 url: '/backend/call',
 method: 'POST'
})
.then(response => {
    // 更新本地状态等操作
    console.log('请求成功', response);
})
.catch(error => {
    // 处理错误,包括用户取消的情况
    console.error('请求失败', error);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:20:48