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

ESP32认证系统仅iOS Safari页面刷新后丢失Cookie问题排查

ESP32基础认证系统iOS浏览器兼容问题解决记录

系统概述

我为ESP32开发了一套基础认证系统:用户在网页输入凭证,后端验证通过后设置带有session ID的Cookie,随后页面立即刷新。

ESP32后端Cookie设置函数

void setCookie(AsyncWebServerResponse* response, const char* name, const char* value, int secondsFromNow) {
    time_t now = time(nullptr);
    time_t expirationTimestamp = now + secondsFromNow;

    // 将过期时间戳转换为"expires"属性的格式化字符串
    struct tm* tmInfo = gmtime(&expirationTimestamp);
    char expires[128];
    strftime(expires, sizeof(expires), "%a, %d %b %Y %H:%M:%S GMT", tmInfo);

    // 设置带有"expires"属性的Cookie
    char cookie[512];  // 根据需要调整缓冲区大小
    snprintf(cookie, sizeof(cookie), "%s=%s; expires=%s; path=/", name, value, expires);
    response->addHeader("Set-Cookie", cookie);

    printf("[Server] - Set cookie: %s\n", cookie);
}

函数输出示例:Set cookie: sessionID=2B945041-3DF6-454A-BC37-2C72A0C46150; expires=Mon, 27 Nov 2023 10:36:14 GMT; path=/

前端提交后刷新代码

form.addEventListener('submit', async function(e){
    e.preventDefault();
    if( isLoading ){return;}
    const username = usernameElem.value;
    const password = passwordElem.value;
    if( username === "" || password === "" ){
        return setError(lang.getWord("emptyInput"));
    }
    setLoading(true);
    const resp = await fetch("/auth/login", {
        method: "POST",
        headers: {
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            username: username,
            password: password
        })
    });
    setLoading(false);
    if( resp.ok ){
        setTimeout(() => {
            location.reload();
            //window.location.href = "/";
        },500);
    }else{
        return setError(lang.getWord("wrongUsernameOrPassword"));
    }
}, false);

测试情况

  • Android端Chrome、Firefox、Opera:均正常运行
  • Windows端Chrome、Opera、Edge、Firefox、Brave:均正常运行
  • iOS端Safari及其他浏览器:无法正常工作

页面刷新后,后端会检查session ID完成登录,若未找到则返回登录页,但iOS浏览器始终返回登录页。

已尝试的解决方法

  • 设置/取消Cookie的path、domain属性
  • 调整前端页面刷新的延迟时间
  • 使用window.location.href = "/"替代location.reload()
  • 增减Cookie字符串末尾的分号
  • 添加SameSite、HttpOnly属性(前者使问题更严重,后者无效果)

问题根因及临时解决

最终定位问题出在getCookie方法:不同平台的Cookie顺序不同,原基于C字符串的解析逻辑存在缺陷。原方法代码如下:

boolean HsH_Server::getCookie(const char* name, const char* cookie, const char*& result) {
    if (name == nullptr || cookie == nullptr ||
        strlen(name) == 0 || strlen(cookie) == 0) {
        return false;
    }
    const char* position = strstr(cookie, name);
    if (position == nullptr) {
        return false;
    }

    // 计算跳过名称和'='后的起始位置
    position += strlen(name) + 1;

    // 找到结束位置(下一个';'或Cookie字符串末尾)
    const char* endPos = strchr(position, ';');
    if (endPos == nullptr) {
        // 如果没有';',说明这是最后一个Cookie
        endPos = cookie + strlen(cookie);
    }

    // 计算Cookie值的长度
    size_t length = endPos - position;

    // 设置result指针指向Cookie值的起始位置
    result = position;

    return true;
}

改用String版本的解析方法后问题暂时解决,但我希望避免使用String:

boolean HsH_Server::getCookie(String name, String cookie, String& result) {
    int position = cookie.indexOf(name);
    if (position == -1) {
        return false;
    }
    name += "=";
    int length = name.length();
    int startPos = position + length;
    int stopPos = cookie.indexOf(";", startPos);
    result = cookie.substring(startPos, stopPos);
    return true;
}

内容的提问来源于stack exchange,提问作者Dr.Random

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 15:04:55