logo科技微讯

阿里云函数 3.0 自定义域名请求失败的问题

作者:科技微讯
日期:2024-01-02
📝 笔记

2023 年 10 月底,阿里云栖大会发布了阿里云函数 3.0 版,这是一个大版本升级

我最近也把部分函数升级到了 3.0,其中一个函数用作 API 供网站调用,绑定了自定义域名,但升级后发现网页无法像之前那样成功发起网络请求。

简单调查后发现是浏览器的 CORS 机制导致的,但根据 FC 3.0 的文档,阿里云函数默认是允许跨域请求的,函数的 HTTP 触发器确实支持浏览器发起跨域请求,只是自定义域名不支持。可能是 FC 3.0 对自定义域名的处理机制和之前版本不同的原因。

cors_explain

所谓跨域请求,是指向不同于主域发起的请求。浏览器不会阻止和主域相同的请求,但对于跨域请求,浏览器会先发起预检请求,即 preflight request,目的是问服务器:大哥,你同意我发起跨域请求啊?服务器需要返回合适的 headers 以表示同意或拒绝。如果同意,浏览器才会发起正式请求,如果不同意,浏览器就不会发起正式请求。

我的这个 API 升级到 3.0 之后,由于绑定了自定义域名,就拒绝了浏览器发起的 preflight 请求,如果绑定的是 FC 内置的 HTTP 触发器就不会拒绝。

要解决自定义域名的这个问题也很简单,根据阿里云函数的文档,开发者可以在函数的代码中自定义函数对跨域请求的处理行为。具体来说,就是当请求 method 为 OPTIONS 时(因为 preflight 请求的方法就是 OPTIONS),返回一个值为 *Access-Control-Allow-Origin 响应头。

下面的代码来自 vercel 的文档,和阿里云函数不完全相同,但思路一样,可供参考:

const allowCors = (fn) => async (req, res) => {
  res.setHeader("Access-Control-Allow-Credentials", true);
  res.setHeader("Access-Control-Allow-Origin", "*");
  // another common pattern
  // res.setHeader('Access-Control-Allow-Origin', req.headers.origin);
  res.setHeader(
    "Access-Control-Allow-Methods",
    "GET,OPTIONS,PATCH,DELETE,POST,PUT"
  );
  res.setHeader(
    "Access-Control-Allow-Headers",
    "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
  );
  if (req.method === "OPTIONS") {
    res.status(200).end();
    return;
  }
  return await fn(req, res);
};

const handler = (req, res) => {
  const d = new Date();
  res.end(d.toString());
};

module.exports = allowCors(handler);

CORS 是浏览器的一种机制,其他客户端通常没有这个机制,这些客户端不会发起 preflight 请求,即不会先征求 API 是否支持跨域请求,而是直接发起正式请求。

donation赞赏
thumbsup0
thumbsdown0
暂无评论