Cloud Functions for Firebase: 'Error: could no

2019-01-26 05:35发布

I feel like pulling my hair out; this is either super simple and i'm having brain freeze or it is not that simple.

What I want

I am trying to unshorten a shortened URL using firebase, when a user goes to:
myapp.firebaseappurl.com/url/SHORTENEDLINK
SO wont let me add a shortened URL

I would like the output to be:

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

What I have tried

firebase.json file:

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

index.js file:

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);
      }
    );

});

Result

When I go to myapp.firebaseappurl.com/url/SHORTENEDLINK I get the following:

Error: could not handle the request

4条回答
时光不老,我们不散
2楼-- · 2019-01-26 06:07

You are seeing Error: could not handle the request since there probably was an exception and it timed out.

Check your logs using:

firebase functions:log

Refer docs for more details

Here's how I got URL unshortening to work

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 });
    }
  });
});

You can follow the hello world example straight away and use the above code as your function.

Above code uses HEAD requests to peek into 'Location` field of the headers and decides if the url can be further unshortened.

This is lighter as HEAD requests ask for no body (thereby avoiding body parsing). Also, no third party lib required!

Also note that the url passed as a query param. So the request would be

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

Saves you the trouble of URL re-writes. Plus semantically makes a little more sense.

查看更多
甜甜的少女心
3楼-- · 2019-01-26 06:09

I think your code is fine. What you're doing incorrectly is that you're using Express-js notations in your firebase.json's rewrites node. (the :item part). These don't work in the Firebase Realtime Database.

So, instead of doing that, change your firebase.json to the following :-

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

This is also the advocated approach in the Cloud Functions for Firebase's URL Shortener sample.

查看更多
姐就是有狂的资本
4楼-- · 2019-01-26 06:21

First make sure you are receiving the request properly with the shortened 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);

Now when you visit myapp.firebaseappurl.com/url/SHORTENEDLINK you should see the SHORTENEDLINK in plain text. When that's working, try the redirect.

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);

Also it's good practice to npm install with --save so they end up in the packages.json. While firebase copies your node_modules folder, most other SaaS platforms run npm install.

查看更多
唯我独甜
5楼-- · 2019-01-26 06:22

Did you tried using { source: '/url/**' } syntax?

You can use something like this;

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

and then you can parse the url from the request.

 exports.url = functions.https.onRequest((req, res) => { 
   // parse the url from the req and redirect to the correct link
 });
查看更多
登录 后发表回答