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

Google Apps Script自定义函数GET_REDIRECT_LOCATION无法处理Meta Refresh重定向及URL对象报错的修复方案咨询

Google Apps Script自定义函数GET_REDIRECT_LOCATION无法处理Meta Refresh重定向及URL对象报错的修复方案咨询

我看到你在使用Google Apps Script自定义函数GET_REDIRECT_LOCATION时遇到了两个核心问题:一是处理Meta Refresh重定向时抛出ReferenceError: URL is not defined错误,二是部分URL无法正确识别重定向地址。让我一步步帮你排查并修复这些问题:

问题1:URL对象未定义的原因及修复

Google Apps Script默认的旧版Rhino JavaScript引擎不支持ES6引入的URL对象,这就是你触发ReferenceError的直接原因。我们可以通过两种方式解决:

方案A:手动解析Base URL(兼容所有运行环境)

不用URL对象,通过字符串截取的方式手动提取URL的协议和主机部分,替换你代码中所有使用new URL(url)的逻辑:

// 替换原来的URL对象解析逻辑,手动提取协议和主机
function getBaseProtocolAndHost(url) {
  let protocol = 'https://';
  let host = '';
  
  // 提取协议
  const protocolSplit = url.split('://');
  if (protocolSplit.length === 2) {
    protocol = protocolSplit[0] + '://';
    url = protocolSplit[1];
  }
  
  // 提取主机(从开头到第一个/的部分)
  const hostSplit = url.split('/');
  if (hostSplit.length > 0) {
    host = hostSplit[0];
  }
  
  return { protocol, host };
}

然后在处理相对URL时调用这个函数:

// 处理相对URL - 转为绝对路径
if (redirectUrl.startsWith('/')) {
  const { protocol, host } = getBaseProtocolAndHost(url);
  redirectUrl = protocol + host + redirectUrl;
}

方案B:切换到V8运行时(更简洁)

如果你的脚本项目允许,直接切换到V8引擎即可原生支持URL对象:

  1. 打开Apps Script编辑器
  2. 点击右上角的「设置」图标
  3. 勾选「启用新的Apps Script运行时(V8)」
  4. 保存并重新运行脚本

问题2:Meta Refresh重定向正则匹配优化

你当前的正则表达式/content=["']?\d+;\s*url=([^"'\s>]+)["']?/i可能会遗漏部分Meta Refresh格式,比如未精准匹配http-equiv="refresh"的标签。建议修改为更精准的正则:

// 优化后的Meta Refresh匹配正则,优先匹配带有http-equiv="refresh"的标签
const metaRefresh = content.match(/<meta\s+http-equiv=["']?refresh["']?\s+content=["']?\d+;\s*url=([^"'>]+)["']?/i);

这个正则会先定位到专门的Refresh Meta标签,避免误匹配其他包含content属性的标签。

修复后的完整代码

整合以上修复点,最终的函数代码如下:

/**
 * Returns the redirect location of a url.
 *
 * @param {string} input The source URL being redirected.
 * @return The destination location/URL.
 * @customfunction
 */
function GET_REDIRECT_LOCATION(input) {
  // Basic validation
  if (!input) return "INVALID_URL";
  let url = input.toString().trim();
  if (!url || !url.includes(".")) return "INVALID_URL";

  // Add https if no protocol
  if (!url.startsWith("http")) {
    url = "https://" + url;
  }

  // 辅助函数:手动解析URL的协议和主机
  function getBaseProtocolAndHost(targetUrl) {
    let protocol = "https://";
    let host = "";
    
    const protocolSplit = targetUrl.split("://");
    if (protocolSplit.length === 2) {
      protocol = protocolSplit[0] + "://";
      targetUrl = protocolSplit[1];
    }
    
    const hostSplit = targetUrl.split("/");
    if (hostSplit.length > 0) {
      host = hostSplit[0];
    }
    
    return { protocol, host };
  }

  try {
    // First try with followRedirects: false to catch HTTP redirects
    let response = UrlFetchApp.fetch(url, {
      muteHttpExceptions: true,
      followRedirects: false
    });
    let status = response.getResponseCode();

    // Check for HTTP redirect (3xx status codes)
    if (status >= 300 && status < 400) {
      const headers = response.getAllHeaders();
      const location = headers.Location || headers.location;
      if (location) {
        return location;
      }
    }

    // Get the HTML content to check for meta redirects
    const content = response.getContentText();

    // 优化后的Meta Refresh匹配逻辑
    const metaRefresh = content.match(/<meta\s+http-equiv=["']?refresh["']?\s+content=["']?\d+;\s*url=([^"'>]+)["']?/i);
    if (metaRefresh && metaRefresh[1]) {
      let redirectUrl = metaRefresh[1];
      // Handle relative URLs - make them absolute
      if (redirectUrl.startsWith('/')) {
        const { protocol, host } = getBaseProtocolAndHost(url);
        redirectUrl = protocol + host + redirectUrl;
      }
      return redirectUrl;
    }

    // Check for canonical URL as backup
    const canonical = content.match(/<link[^>]*rel=["']canonical["'][^>]*href=["']([^"']+)["']/i);
    if (canonical && canonical[1]) {
      let canonicalUrl = canonical[1];
      // Handle relative URLs
      if (canonicalUrl.startsWith('/')) {
        const { protocol, host } = getBaseProtocolAndHost(url);
        canonicalUrl = protocol + host + canonicalUrl;
      }
      if (canonicalUrl !== url) {
        return canonicalUrl;
      }
    }

    return "NO_REDIRECTS_FOUND";
  } catch (error) {
    return "ERROR: " + error.toString();
  }
}

额外优化建议

  1. 处理带参数的相对URL:如果遇到类似../path的相对路径,当前逻辑无法处理,你可以进一步补充相对路径解析逻辑
  2. 增加超时设置:在UrlFetchApp.fetch的参数中添加timeout: 10000(10秒超时),避免因目标服务器响应慢导致函数卡死
  3. 验证重定向URL有效性:返回重定向地址前,可以额外验证地址格式,避免返回无效路径

用你提供的VSCode博客URL测试修复后的函数,应该能正确返回完整的目标重定向地址。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 06:43:09