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

iPhone Safari需关闭跨站追踪才能使用电商APP心愿单功能问题

iPhone Safari 跨站追踪阻止导致HTTP-only Cookie身份认证失效问题

问题场景

开发的React+Node.js电商APP,前端部署在Vercel,后端部署在Render,采用HTTP-only Cookie实现身份认证,包含心愿单添加与查看功能。桌面端所有主流浏览器(Chrome、Edge、Firefox、Safari)功能正常,但在iPhone Safari中,必须手动关闭「阻止跨站追踪」设置,心愿单功能才能正常使用。

具体问题:iPhone Safari可正常完成登录,但调用POST /user/wishlist添加商品至心愿单或GET /user/wishlist查看心愿单时,请求静默失败或未携带认证Cookie,仅关闭跨站追踪设置后恢复正常。

相关代码

后端代码

app.use(
  cors({
    origin: [
      'https://e-shop-drab.vercel.app', // Vercel生产域名
      'http://localhost:5173', // 开发环境域名
      'https://eshop-vqu6.onrender.com' // 测试用Ngrok域名
    ],
    methods: ['GET', 'POST', 'OPTIONS'], 
    credentials: true,
    allowedHeaders: ['Content-Type', 'Authorization']
  })
);

const cookieParser = require('cookie-parser');    
app.use(cookieParser());

const jwt = require('jsonwebtoken');

const generateTokenAndSetCookie = (userId, res) => {
    const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
        expiresIn: '1h',
    });
    
    res.cookie('token', token, {
        httpOnly: true,
        secure: true,
        sameSite: 'None',
        maxAge: 3600 * 1000,
    });

    return token;
};

module.exports = generateTokenAndSetCookie;

前端代码

import axios from 'axios';

const api  = axios.create({
    baseURL: "https://eshop-vqu6.onrender.com",
    withCredentials: true,
    headers: {
        'Content-Type': 'application/json'
      }
})

const CheckLogin = () => api.get("/user/check-login");
const PostSignup = (signup) => api.post("/user/signup",signup);
const PostLogin = (login) => api.post("/user/login",login);
const Logout = () => api.post("/user/logout",{}, { withCredentials: true });

const addToWishList = (wishlist) => api.post("/user/wishlist",wishlist,{ withCredentials: true });
const getWishlist = () => api.get("/user/wishlist",{ withCredentials: true });
const removeWishlist = (productID) => api.post("/user/removewishlist",{ productID });

export {CheckLogin, PostSignup, PostLogin,Logout,addToWishList,getWishlist,removeWishlist};

问题原因

iPhone Safari的「阻止跨站追踪」(ITP,Intelligent Tracking Prevention)机制会严格限制跨域场景下的第三方Cookie。当前前端(Vercel域名)与后端(Render域名)属于跨域,即便Cookie设置了sameSite: None和secure: true,ITP仍会将其标记为跨站追踪Cookie,在后续请求中自动拦截不携带,导致身份认证失败,心愿单接口无法正常调用。

解决方案

方案1:为Cookie添加Partitioned属性

Safari 15.4及以上版本支持Partitioned属性,配合sameSite: None和secure: true使用,可让跨域Cookie绕过ITP限制,在请求中正常携带。修改后端generateTokenAndSetCookie函数中的Cookie配置:

res.cookie('token', token, {
    httpOnly: true,
    secure: true,
    sameSite: 'None',
    maxAge: 3600 * 1000,
    Partitioned: true, // 新增该属性
});

方案2:优化CORS配置

  • 确保CORS的origin数组包含前端实际请求的完整域名,避免使用通配符;
  • 补充接口用到的HTTP方法,确保预检请求(OPTIONS)正常通过;
  • 移除未实际使用的请求头配置,减少冗余:
app.use(
  cors({
    origin: [
      'https://e-shop-drab.vercel.app',
      'http://localhost:5173',
    ],
    methods: ['GET', 'POST', 'OPTIONS'],
    credentials: true,
    allowedHeaders: ['Content-Type'], // 若未使用Authorization可移除
    optionsSuccessStatus: 200, // 兼容旧版本浏览器
  })
);

方案3:统一前端axios配置

axios实例已设置withCredentials: true,后续请求无需重复配置,可简化代码避免遗漏:

const api = axios.create({
    baseURL: "https://eshop-vqu6.onrender.com",
    withCredentials: true,
    headers: {
        'Content-Type': 'application/json'
    }
})

// 简化请求方法,无需重复设置withCredentials
const addToWishList = (wishlist) => api.post("/user/wishlist", wishlist);
const getWishlist = () => api.get("/user/wishlist");

方案4:同站部署(根源解决)

若条件允许,将前端和后端部署在同一主域名下(如前端shop.yourdomain.com,后端api.shop.yourdomain.com),此时属于同站请求,Safari的ITP不会拦截Cookie,彻底解决跨域Cookie问题。

验证步骤

  1. 修改代码后重新部署后端和前端;
  2. 在iPhone Safari中开启「阻止跨站追踪」设置;
  3. 登录后尝试添加/查看心愿单,检查请求是否携带token Cookie,确认接口正常响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 13:53:16