如何避免 javascript 设置 cookie 函数是 overriding/deleting 以前的 cookie

How to avoid that a javascript set cookie function is overriding/deleting previous cookie

我正在 Javascript 到 setCookie 中构建一个函数,我遇到了这个问题,当我尝试在同一个文件中为 2 个 cookie setCookie 时,第二次调用设置 cookie 删除前 setCookie 个值。

我的setCookie函数

import { serialize } from 'cookie';

export default function setCookie(res, name, value, options = {}) {
  console.log('SET COOKIE', name, value); 
  const stringValue =
    typeof value === 'object' ? 'j:' + JSON.stringify(value) : String(value);

  if ('maxAge' in options) {
    options.expires = new Date(Date.now() + options.maxAge);
    options.maxAge /= 1000;
  }

  console.log(stringValue);

  res.setHeader('Set-Cookie', serialize(name, String(stringValue), options));
}

并且setCookie在下面的方法中被用作

setCookie(res, 'conversationId', conversation.id, {
          path: '/api',
          httpOnly: true,
        });
    
setCookie(res, 'memberId', member.id, {
          path: '/api',
          httpOnly: true,
        });

第一个 setCookie 未显示在浏览器 cookie 中,但第二个显示。 我没有看到 conversationId,只有 memberId。 似乎第二个调用删除了第一个。

完整方法

const getHandler = async (req, res) => {
  try {
    const recipientIds = parseRecipientIds(req.cookies.recipientIds);
    const documentId = req.query.id;

    const doc = await getIcfDocument(documentId);
    if (!doc) {
      log.warn('Document %s could not be retrieved', documentId);
      return res
        .status(400)
        .json({ message: 'Document could not be retrieved' });
    }

    // TODO some docs don't have recipients?
    const recipient = doc.Consentee.recipients.find((x) =>
      recipientIds.includes(x.id)
    );

    await addActivity({
      activityTypes: ['recipient_link_opened'],
      activityOwnerType: 'DOCUMENT',
      activityOwnerId: documentId,
      documentId,
      metadata: {
        recipientId: recipient?.id,
      },
    });

    const { conversation, member } = await joinConsentConversation(
      doc,
      recipient
    );
    if (!conversation) {
      log.warn('Recipient %o could not join conversation', recipient);
      return res.status(400).json({ message: 'Could not join conversation' });
    }

    console.log('CONVERSATION HERE...', conversation);

    const consenteeData = {
      document: doc,
      conversation,
      recipientId: recipient.id,
    };

    console.log(member.id, conversation.id);

    setCookie(res, 'conversationId', conversation.id, {
      path: '/api',
      httpOnly: true,
    });

    setCookie(res, 'memberId', member.id, {
      path: '/api',
      httpOnly: true,
    });

    log.info('Recipient %s document %s logged in', recipient.id, doc.id);
    return res.status(200).json(consenteeData);
  } catch (err) {
    log.error('handle form %s', err.message);
    return res.status(500).json(res.data?.errors);
  }
};

作为我在方法函数中执行 console.log(...) 时的额外信息,这就是结果

CONVERSATION HERE... { id: '17', status: 'EMPTY', messages: { nodes: [] } }
21 17
SET COOKIE conversationId 17
17
SET COOKIE memberId 21
21

当我在浏览器中检查 cookie 时,我没有看到对应于 conversation.id17。该值未在 cookie 中设置,我不知道为什么。

这实际上是正确的行为,因为您 设置了 一个值,而不是将值附加到 headers。

来自NodeJS documentation

If this header already exists in the to-be-sent headers, its value will be replaced. Use an array of strings here to send multiple headers with the same name.

因此,解决方案就在文档中。

更改 setCookie 函数中的以下行:

res.setHeader('Set-Cookie', serialize(name, String(stringValue), options));

至:

let cookieValues = res.getHeader('set-cookie') || [];
if (typeof cookieValues === 'string') {
  cookieValues = [cookieValues];
}
cookieValues.push(serialize(name, String(stringValue), options));
res.setHeader('Set-Cookie', cookieValues);