无法从 fetch() 响应访问 cookie

Unable to access cookie from fetch() response

尽管这个问题在 SO 被问了好几次,比如:


Unable to set cookie in browser using request and express modules in NodeJS

None 的解决方案可以帮助我从 fetch() 响应

中获取 cookie

我的设置如下所示:

客户

export async function registerNewUser(payload) {
    return fetch('https://localhost:8080/register',
        {
            method: 'POST',
            body: JSON.stringify(payload),
            credentials: 'same-origin',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            }
        });
}

...
function handleSubmit(e) {
    e.preventDefault();

    registerNewUser({...values, avatarColor: generateAvatarColor()}).then(response => {
        console.log(response.headers.get('Set-Cookie')); // null
        console.log(response.headers.get('cookie')); //null
        console.log(document.cookie); // empty string
        console.log(response.headers); // empty headers obj
        console.log(response); // response obj
    }).then(() => setValues(initialState))
}

服务器

private setUpMiddleware() {
    this.app.use(cookieParser());
    this.app.use(bodyParser.urlencoded({extended: true}));
    this.app.use(bodyParser.json());
    this.app.use(cors({
        credentials: true,
        origin: 'http://localhost:4200',
        optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
        credentials: true
    }));
    this.app.use(express.static(joinDir('../web/build')));
}
...
this.app.post('/register', (request, response) => {
    const { firstName, lastName, avatarColor, email, password }: User = request.body;
    this.mongoDBClient.addUser({ firstName, lastName, avatarColor, email, password } as User)
        .then(() => {
            const token = CredentialHelper.JWTSign({email}, `${email}-${new Date()}`);
            response.cookie('token', token, {httpOnly: true}).sendStatus(200); // tried also without httpOnly
        })
        .catch(() => response.status(400).send("User already registered."))
})

JavaScript fetch 方法不会发送客户端 cookie 并默默地忽略服务器端 Reference link in MDN 发送的 cookie,因此您可以使用 XMLHttpRequest 方法发送来自您客户端的请求。

我明白了。解决方案是将凭据设置为 'include',如下所示:

export async function registerNewUser(payload) {
    return fetch('https://localhost:8080/register',
        {
            method: 'POST',
            body: JSON.stringify(payload),
            credentials: 'include',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            }
        });
}

之后我需要在我的 cors 中间件中启用凭据:

    this.app.use(cors({
            credentials: true, // important part here
            origin: 'http://localhost:4200',
            optionsSuccessStatus: 200 
        })

然后最后我需要删除快速路由响应中的选项 {httpOnly: true}

response.cookie('token', '12345ssdfsd').sendStatus(200);

请记住,如果您像这样发送 cookie,它会直接设置为客户端 cookie。您现在可以看到 cookie 设置为:console.log(document.cookie).

但在实际环境中,您不想发送客户端可访问的 cookie。您通常应该使用 {httpOnly: true} 选项。