Firebase的云函数:'错误:无法处理请求'

27

我感觉要把头发都拔光了;这可能非常简单,但我脑子一片空白,或者它并不那么简单。

我的需求

我正在尝试使用 Firebase 解除缩短的 URL。当用户访问以下网址时:
myapp.firebaseappurl.com/url/SHORTENEDLINK
SO 不允许我添加缩短的 URL

我希望输出结果为:

{
  "url": "https://stackoverflow.com/questions/45420989/sphinx-search-how-to-use-an-empty-before-match-and-after-match"
}

我的尝试

firebase.json文件:

{
  "hosting": {
    "public": "public",
    "rewrites": [ {
    "source": "/url/:item",
      "destination": "/url/:item"
    } ]
  }
}

index.js 文件:

const functions = require('firebase-functions');

exports.url = functions.https.onRequest((requested, response) => {

    var uri = requested.url;
    request({
        uri: uri,
        followRedirect: true
      },
      function(err, httpResponse) {
        if (err) {
          return console.error(err);
        }
        response.send(httpResponse.headers.location || uri);
      }
    );

});

结果

当我访问myapp.firebaseappurl.com/url/SHORTENEDLINK时,我会看到以下内容:

Error: could not handle the request

1
method: 'POST' 添加到请求中。 - mohamad rabee
为什么?传递的参数在URL中,所以这是一个GET请求,对吗? - JamesG
@mohamadrabee - 还有,我刚试了一下看看是不是这个问题。不是的,没有起作用。 - JamesG
抱歉,我的错误。 - mohamad rabee
请求不在我的package.json文件中,但我在functions文件夹中使用npm install request安装了它,并且它已经存在 :) - JamesG
显示剩余4条评论
5个回答

20

您看到了错误:无法处理请求,这可能是由于异常和超时引起的。

请使用以下命令检查日志:

firebase functions:log

请参考更多详细信息,请点击文档

以下是我如何使URL还原正常工作的方法。

const functions = require('firebase-functions');

const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

const http = require('http');
const urlP = require('url');

const unshorten = (url, cb) => {
  const _r = http.request(
    Object.assign(
      {},
      urlP.parse(url),
      {
        method: 'HEAD',
      }
    ),
    function(response) {
      cb(null, response.headers.location || url);
    }
  );
  _r.on('error', cb);
  _r.end();
};

const resolveShortUrl = (uri, cb) => {
  unshorten(uri, (err, longUrl) => {
    if (longUrl === uri) {
      cb(null, longUrl);
    } else {
      resolveShortUrl(longUrl, cb);
    }
  });
};

exports.url = functions.https.onRequest((requested, response) => {
  var uri = requested.query.url;
  resolveShortUrl(uri, (err, url) => {
    if (err) {
      // handle err
    } else {
      response.send({ url });
    }
  });
});

您可以直接跟随Hello World示例,使用上面的代码作为您的function

上面的代码使用HEAD请求来查看头部的“Location”字段,并决定是否可以进一步展开url。

这样做更轻量级,因为HEAD请求不要求body(从而避免了body解析)。另外,无需第三方库!

还要注意url作为查询参数传递。所以请求将是

http://<your_firebase_server>/url?url=<short_url>

省去了URL重写的麻烦。此外,语义上也更加合理。


我认为需要重写代码,以便告诉我的 Firebase Hosting 基于哪个 URL 运行哪个函数? - JamesG
尝试一下这个 https://us-central1-helloworld-9d223.cloudfunctions.net/url?url=<短链接> - user2065736
@JamesG 你有机会尝试这个解决方案了吗? - user2065736

2

你尝试过使用{ source: '/url/**' }语法吗?

你可以像这样使用:

{
  "hosting": {
    "public": "public",
    "rewrites": [ {
    "source": "/url/**",
    "function": "/url"
    }]
  }
}

然后您可以从请求中解析出URL。
 exports.url = functions.https.onRequest((req, res) => { 
   // parse the url from the req and redirect to the correct link
 });

2

在 firebase.json 中尝试以下内容,这对我很有效:

"最初的回答"

"source": "/**",

我也尝试了"source": "/url/**",但它没有起作用。最初的回答。

0

首先,请确保您已正确接收缩短的URL请求。

const functions = require('firebase-functions');

const express = require('express');
var express_app = express();
express_app.use(body_parser.text({type: ()=>true}));
express_app.all('*', (req, res) => {
    console.log(req.path);
    res.send(JSON.stringify(req.path));
});
exports.url = functions.https.onRequest(express_app);

现在当你访问 myapp.firebaseappurl.com/url/SHORTENEDLINK 时,应该会看到明文的 SHORTENEDLINK。当这个功能正常工作后,请尝试进行重定向。
const functions = require('firebase-functions');
const express = require('express');
const request = require('request');
var express_app = express();
express_app.use(body_parser.text({type: ()=>true}));
express_app.all('*', (req, res) => {
    var url = req.path;
    request({
        uri: uri,
        followRedirect: true
      },
      function(err, httpResponse) {
        if (err) {
          return console.error(err);
        }
        res.send(httpResponse.headers.location || uri);
      }
    );
});
exports.url = functions.https.onRequest(express_app);

另外,将--savenpm install一起使用是一个好的实践方法,这样它们就会出现在packages.json中。虽然firebase会复制您的node_modules文件夹,但大多数其他SaaS平台都运行npm install


0

我认为你的代码没问题。你做错了的是,在你的 firebase.json 文件中的 rewrites 节点中使用了 Express-js 的标记(:item 部分)。这些在 Firebase 实时数据库中不起作用。

因此,你需要将你的 firebase.json 改为以下内容:

 {
  "hosting": {
    "public": "public",
    "rewrites":  {
    "source": "YOUR SHORTENED URL",
    "destination": "YOUR ORIGINAL URL"
  } 
  }
}

这也是 Cloud Functions for Firebase 的 URL 短链接器 示例 中提倡的方法。


这不会是动态的。我想能够将URL作为参数传递给函数。有什么想法吗? - JamesG
@Rohan 这个示例仅适用于 goo.gl 链接。此外,可以使用 HEAD 请求来解析 URL,这比 GET 请求更轻量级。 - user2065736
@JamesG 是的,它不会是动态的。但是,每当您缩短URL时,您可以将原始URL简单保存在指定位置。要访问原始URL,您只需在Cloud函数文件中添加代码,在HTTP触发期间从指定位置读取它,并将其用作响应的URL。当然,这不会是动态的。但是,您无需即时还原URL,也无需包含第三方应用程序。 - Rohan Stark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接