1

这是我关于stackoverflow的第一个问题,所以请温柔一点。我正在使用 node.js 构建一个简单的应用程序,该应用程序依赖于对外部地理编码服务的 API 调用。我的程序在本地运行,但在部署到 heroku 时失败。这是失败的功能:

async function geoEncode(restaurant = false, string = false) {
  let address;
  address = (string) ? string : require('querystring').escape(`${restaurant.street_address}, ${restaurant.city_state_zip}, ${restaurant.state}, ${restaurant.zip}`);
  let url = await geoApi.replace("SEARCH_STRING", address);
  let encodedURL = new URL(url);
  let init = {};
  let headers = {
    "async": true,
    "crossDomain": true,
    "method": "GET",
    "Host": "us1.locationiq.com",
  }
  init.headers = headers;
  try {
    let response = await fetch(encodedURL.href, init);
    let output = await response.json();
    return output;
  } catch(err){
    console.log("this log an error in geoEncode", err);
  }
}

我认识到这段代码目前是一堆不必要的编码和冗余标头。我失败的调试过程的副作用。在本地运行时,程序会向服务发送一个有效的 url 并返回响应数据。当部署在heroku上时,

let encodedURL = new URL(url);

投掷

TypeError [ERR_INVALID_URL]: Invalid URL: "https://us1.locationiq.com/v1/search.php?key ...

我已经为我的问题编辑了这个 url 以保护 API 密钥,但是当我使用那个字符串(减去引号)并通过我的浏览器运行它时,它会返回有效的 JSON。

在部署之前,我根本没有对我的 url 进行任何编码 - 我只是构建了一个字符串并将其提供给 node-fetch 模块的 fetch 方法。它在 Heroku 上出错,显示消息“TypeError:仅支持绝对 URL”。从那以后,我了解到此错误消息意味着 node-fetch 的请求方法无法解析协议或主机名。我已经设法确定,当部署在 heroku 上时,它无法解析两者。

我的本地环境和 heroku 的明显区别在于我通过 heroku 的仪表板而不是通过我的 .env 文件设置了环境变量。因为我有点不清楚它是如何工作的,所以我最近的大部分调试都试图确保我提供给 fetch API 的字符串是一致的、统一的编码。因此,我已经预先转义了我的代码,手动对其进行了 utf8 编码,通过 URL 模块运行它,并将该 url 编码的输出输入到函数中而无需触摸它。它仍然在本地工作并在远程失败。

我的基本堆栈是 MongoDB、Express、Node、Bootstrap。我对我的云 MongoDB 服务器进行的调用以及对我从中获取地理编码数据的 API 的调用也是如此。只有这些对我的地理编码服务的调用失败,所以我用于 MongoDB 连接的环境变量按预期运行。

谢谢你的帮助!

编辑1:

为了回答下面的评论(对我尝试的评论答案的格式感到抱歉;我现在知道markdown 格式在评论中受到限制),我发布的错误是使用命令“heroku logs --tail”从heroku 记录的。我已经手动记录了我要编码的 URL(下面是一个经过编辑的示例):

URL to be encoded: "https://us1.locationiq.com/v1/search.php?key=KEY-REDACTED&format=json&q=101%20NICKERSON%20ST%2C%20SEATTLE%2C%20WA%2C%2098109-1654"

以及heroku报告的错误:

TypeError [ERR_INVALID_URL]: Invalid URL: "https://us1.locationiq.com/v1/search.php?key=KEY-REDACTED=json&q=101%20NICKERSON%20ST%2C%20SEATTLE%2C%20WA%2C%2098109-1654"

编辑2:

我想我可能没有在我的帖子中提供足够的错误日志记录。这是更完整的错误日志。我希望这对可以反过来帮助我的人有所帮助。

2019-11-14T23:35:09.646585+00:00 app[web.1]: (node:23) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_URL]: Invalid URL: "https://us1.locationiq.com/v1/search.php?key=KEY_REDACTED&format=json&q=101%20NICKERSON%20ST%2C%20SEATTLE%2C%20WA%2C%2098109-1654"
2019-11-14T23:35:09.646591+00:00 app[web.1]: at onParseError (internal/url.js:243:9)
2019-11-14T23:35:09.646593+00:00 app[web.1]: at new URL (internal/url.js:319:5)
2019-11-14T23:35:09.646595+00:00 app[web.1]: at geoEncode (/app/server.js:308:20)
2019-11-14T23:35:09.646599+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_queues.js:93:5)
2019-11-14T23:35:09.646602+00:00 app[web.1]: at async Timeout._onTimeout (/app/server.js:373:29)

4

1 回答 1

0

解决!答案是可以预见的枯燥乏味,但这里是:

当我在 heroku 仪表板中输入引用为 geoAPI 的环境变量时,我将其作为带引号的字符串输入。Heroku 必须已经将环境变量键入为字符串,因为结果是以 "" 开头和结尾的字符串,这导致 url 模块无法解析。当我在控制台记录 querystring.parse(url) 的输出并收到以下信息时,我最终发现了这个问题:

parsed querystring: [Object: null prototype] {
2019-11-19T21:54:59.724380+00:00 app[web.1]: '"https://us1.locationiq.com/v1/search.php?key': 'REDACTED',
2019-11-19T21:54:59.724382+00:00 app[web.1]: format: 'json',
2019-11-19T21:54:59.724385+00:00 app[web.1]: q: '101 NICKERSON ST, SEATTLE, WA, 98109-1654"' }

显然,额外的引号使第一个“=”之前的所有内容都被读作键。这就是我发现额外引号的方式。删除多余的引号解决了这个问题。很高兴它结束了,但遗憾的是它只是 heroku 仪表板中的格式错误。

我从中得到的小教训:不要把你的heroku环境变量放在引号中。他们不是这样工作的。

我从中得到的重要教训:当某些事情很神秘时,请尽早检查您的环境。如果你检查它,没有发现任何东西,并且长时间停留在问题上,请再次检查它。

于 2019-11-19T22:31:57.703 回答