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

JS Fetch返回result为undefined问题排查求助

问题排查:部分iOS Safari用户调用Fetch API时出现"result = undefined"错误

问题概述

代码对绝大多数用户正常运行,但部分使用iOS 16.6系统的Mobile Safari用户遇到错误,日志显示Error: result = undefined。

后端Express.js代码

router.post("/do-something", async (req, res) => {
    res.status(200).send({
        token: '8lAp5hVLUXZFq/laslTWd+GOEcEOeJ58X+Eu2Elg0Q',
        expirationDate: 1695680882748,
        email: 'manu.macron@gmail.com'
    });
})

router.post("/error-log", async (req, res) => {
    const { error } = req.body
    fs.appendFileSync('logs/something-went-wrong.txt', `${ new Date().toLocaleString() } - ${ error }\n`);
    fs.appendFileSync('logs/something-went-wrong.txt', JSON.stringify(UAParser(req.headers['user-agent']), null, 4) + "\n");
    return res.sendStatus(204)
})

前端Fetch代码

fetch("api.com/do-something", {
    method: "POST",
    headers: {
        'Content-Type': 'application/json',
    }
}).then(async result => {
    const _json = result?.json ? await result.json() : {};
    if(!result?.ok) {
        const error = new Error(result?.statusText || "result = undefined")
        error.code = result?.status || 418
        error.details = Object.keys(_json).length ? _json : null
        throw error;
    }
    // Do something with the token
}).catch(error => {
    fetch("api.com/error-log", {
        method: "POST",
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({ error: `Someone did fetch but ${error?.details ? JSON.stringify(error.details) : (error instanceof Error ? error.toString() : error)}` })
    }).then(_ => true /*do nothing*/ )
})

错误日志

# logs/something-went-wrong.txt
29/08/2023 13:57:10 - Someone did fetch but Error: result = undefined
{
    "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1",
    "browser": {
        "name": "Mobile Safari",
        "version": "16.6",
        "major": "16"
    },
    "engine": {
        "name": "WebKit",
        "version": "605.1.15"
    },
    "os": {
        "name": "iOS",
        "version": "16.6"
    },
    "device": {
        "vendor": "Apple",
        "model": "iPhone",
        "type": "mobile"
    },
    "cpu": {}
}

排查分析与调试线索

可能的原因

  1. 浏览器隐私拦截:iOS 16.6的Mobile Safari开启智能跟踪防护(ITP)时,可能会拦截跨域请求或修改响应,导致Response对象的statusText属性缺失,触发错误信息。
  2. URL路径问题:前端Fetch使用相对路径api.com/do-something,缺少协议头(http/https),当页面环境变化时(比如PWA离线模式、不同协议的页面),请求可能异常,导致响应对象不完整。
  3. 网络波动/响应截断:网络不稳定时,响应数据不完整,浏览器无法正确解析Response对象,导致statusText为undefined,result.ok为false。
  4. 前端错误处理逻辑缺陷:result?.json ? await result.json() : {}的判断逻辑有风险,若响应非JSON格式,await result.json()会抛出错误,但当前错误日志未体现这种情况,说明不是主要原因。

调试与修复建议

  • 增强前端错误日志:在错误信息中加入响应的状态码、请求URL、响应头、JSON解析错误等细节,便于定位问题。修改前端代码如下:
    .then(async result => {
        let _json = {};
        const responseDetails = {
            status: result?.status,
            statusText: result?.statusText,
            url: result?.url,
            headers: result?.headers ? Object.fromEntries(result.headers.entries()) : {}
        };
        try {
            _json = await result.json();
        } catch (jsonErr) {
            responseDetails.jsonParseError = jsonErr.toString();
        }
        if (!result?.ok) {
            const error = new Error(result?.statusText || "result = undefined");
            error.code = result?.status || 418;
            error.details = { ...responseDetails, responseBody: _json };
            throw error;
        }
        // 处理token逻辑
    })
    
  • 使用完整URL:将Fetch的目标URL改为带协议的完整路径(如https://api.com/do-something),避免相对路径引发的环境适配问题。
  • 检查后端访问日志:查看后端是否收到这些异常请求,记录请求的IP、头信息、返回状态码,确认请求是否到达后端,或是否被中间层(CDN、代理)修改。
  • 复现测试:使用iOS 16.6的Mobile Safari开启ITP功能,模拟用户环境复现问题,验证是否为隐私拦截导致。
  • 优化后端日志:在/do-something路由中添加请求日志,记录用户UA、请求时间、IP等信息,对比正常请求与异常请求的差异。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 03:29:52