Serve dynamic content and build microservices with Cloud Functions

Pair Firebase Hosting with Cloud Functions for Firebase to host your dynamically generated content and build REST APIs as microservices.

  • Serve dynamic content — In addition to serving static content on your Hosting site, you can serve dynamically generated responses from Cloud Functions that are performing server-side logic.

    For example, you can point a URL pattern (like /blog/<blog-post-id>) to a function that uses the URL's blog post ID parameter to retrieve content dynamically from your database.

  • Build REST APIs — You can create a microservice API using functions. For instance, functions can handle the sign-in functionality for your website. While your website is hosted at /, any request that comes to /api is redirected to your microservice API. For an example, see this open-source sample.

  • Prerender your single-page apps — With prerendering, you can improve SEO and optimize sharing across various social networks by creating dynamic meta tags. To learn more, watch this video or see this open-source sample.

Note that Firebase Hosting is subject to a 60-second request timeout. For dynamic content that might take longer than 60 seconds to generate, consider using the App Engine flexible environment.

Connect Cloud Functions to Firebase Hosting

This section provides a walk-through example for connecting a function to Firebase Hosting.

Note that to improve the performance of your dynamic content, you can optionally tune your cache settings.

Step 1: Set up Cloud Functions

  1. Make sure that:

    • You have the latest version of the Firebase CLI (run npm install -g firebase-tools).

    • You have initialized Firebase Hosting.

    For detailed instructions about installing the CLI and initializing Hosting, see the Get Started guide for Hosting.

  2. If you've already set up Cloud Functions, you can proceed to Step 2: Create an HTTP function.

  3. If you've not already set up Cloud Functions:

    1. Initialize Cloud Functions by running the following command from the root of your project directory:

      firebase init functions
    2. When prompted, select JavaScript (this walk-through example uses JS).

    3. Make sure that you have a functions directory in your local project directory. This functions directory is where the code for Cloud Functions lives.

Step 2: Create an HTTP function to your Hosting site

  1. Open /functions/index.js in your favorite editor.

  2. Replace the file's contents with the following code.

    This code creates an HTTP function (named bigben) that replies to HTTP requests with a BONG for each hour of the day, just like a clock.

    const functions = require('firebase-functions');
    
    exports.bigben = functions.https.onRequest((req, res) => {
      const hours = (new Date().getHours() % 12) + 1  // London is UTC + 1hr;
      res.status(200).send(`<!doctype html>
        <head>
          <title>Time</title>
        </head>
        <body>
          ${'BONG '.repeat(hours)}
        </body>
      </html>`);
    });
    
  3. Deploy this function to your site by running the following command from the root of your project directory:

    firebase deploy

    The function is now reachable at the URL
    https://us-central1-firebase-project-id.cloudfunctions.net/bigben.

Visit the Cloud Functions documentation to learn more about HTTP requests.

In the next step, we walk through how to serve this HTTP function from a Firebase Hosting URL so that it can serve dynamic content for your Firebase Hosting site.

Step 3: Direct hosting requests to your function

With rewrite rules, you can direct requests that match specific patterns to a single destination. For example, to direct all requests from the page /bigben on your Hosting site to execute the bigben function:

  1. Open your firebase.json file.

  2. Add the following rewrite configuration under the hosting section:

    {
     "hosting": {
       // ...
    
       // Add the "rewrites" attribute within "hosting"
       "rewrites": [ {
         "source": "/bigben",
         "function": "bigben"
       } ]
     }
    }
    
  3. Run the firebase deploy command again.

    Your function is now reachable via the URL https://firebase-project-id.firebaseapp.com/bigben (or via https://custom-domain/bigben if you're using a custom domain).

Visit the Hosting configuration page for more details about rewrite rules. You can also learn about the priority order of responses for various Hosting configurations.

Use Express.js

Express.js is a very popular server framework for Node.js. You can use Express.js in Cloud Functions to serve your app's dynamic content and write complex web apps more easily.

This section provides a walk-through example for using Express.js with Firebase Hosting and Cloud Functions.

  1. Install Express.js in your local project by running the following command from your functions directory:

    npm install express --save
  2. Open your /functions/index.js file, then import and initialize Express.js:

    const functions = require('firebase-functions');
    const express = require('express');
    const app = express();
    
  3. Add the following two endpoints:

    1. Add the first endpoint to serve the index of our website at /.

      app.get('/', (req, res) => {
        const date = new Date();
        const hours = (date.getHours() % 12) + 1;  // London is UTC + 1hr;
        res.send(`
          <!doctype html>
          <head>
            <title>Time</title>
            <link rel="stylesheet" href="/style.css">
            <script src="/script.js"></script>
          </head>
          <body>
            <p>In London, the clock strikes:
              <span id="bongs">${'BONG '.repeat(hours)}</span></p>
            <button onClick="refresh(this)">Refresh</button>
          </body>
        </html>`);
      });
      
    2. And another endpoint to return the BONG count as an API, in JSON format, under /api:

      app.get('/api', (req, res) => {
        const date = new Date();
        const hours = (date.getHours() % 12) + 1;  // London is UTC + 1hr;
        res.json({bongs: 'BONG '.repeat(hours)});
      });
      
  4. Export the Express.js app as an HTTP function:

    exports.app = functions.https.onRequest(app);
    
  5. In your firebase.json file, direct all requests to the app function. This rewrite allows Express.js to serve the different subpath that we configured (in this example, / and /api).

    {
     "hosting": {
       // ...
    
       // Add the "rewrites" attribute within "hosting"
       "rewrites": [ {
         "source": "**",
         "function": "app"
       } ]
     }
    }
    

Add Express.js middleware

Now that you're using Express.js, you can add Express.js middleware in the typical way. For example, you can enable CORS requests on our endpoints.

  1. Install the cors middleware by running the following command:

    npm install --save cors
  2. Open your /functions/index.js file, then add cors to your Express.js app, like so:

    const cors = require('cors')({origin: true});
    app.use(cors);
    

Visit the Cloud Functions documentation to learn more about using Firebase with Express apps and middleware modules.

Run dynamic content locally

You can serve and run your HTTP functions locally using the Firebase CLI. This allows you to view and test your Firebase project before deploying to production.

  1. Make sure that both the Firebase CLI and the firebase-functions SDK are the latest versions available. To update both, run the following two commands from the functions directory of your local project:

    npm install -g firebase-tools
    npm install --save firebase-functions@latest
  2. Serve your Firebase project locally by running the following command from the root of your project directory.

    This command emulates hosting and functions on locally hosted URLs.

    firebase serve
When you're using Cloud Functions to generate dynamic content for Firebase Hosting, firebase serve, by default, uses your local HTTP functions as proxies for hosting. For more configuration options for Firebase Hosting and Cloud Functions, see the Firebase CLI Reference.

Using cookies

When using Firebase Hosting together with Cloud Functions, cookies are generally stripped from incoming requests. This is necessary to allow for efficient CDN cache behavior. Only the specially-named __session cookie is permitted to pass through to the execution of Cloud Functions.

When present, the __session cookie is automatically made a part of the cache key, meaning that it's impossible for two users with different cookies to receive the other's cached response. Only use the __session cookie if your function serves different content depending on user authorization.

Manage cache behavior

Firebase Hosting uses a powerful global CDN to make your site as fast as possible.

Any requested static content is automatically cached on the CDN. If you redeploy your site's content, Firebase Hosting automatically clears all your cached static content across the CDN until the next request.

However, because Cloud Functions generate content dynamically, the content for a given URL can vary based on such things as user input or the user's identity. To account for this, requests that are handled by a function do not cache on the CDN by default.

You can, though, configure caching behavior for dynamic content. For example, if a function generates content only periodically, you can speed up your app by caching the generated content for at least a short period of time. You can also potentially reduce function execution costs because the content is served from the CDN rather than via a triggered function. Read more about optimizing function execution in the Cloud Functions documentation.

Learn more about caching behavior in Google's web developer documentation.

Set Cache-Control

The main tool that you use to manage cache for dynamic content is the Cache-Control header. By configuring this header, you can communicate both to the browser and the CDN how long your content can be cached. In your function, you set Cache-Control like so:

res.set('Cache-Control', 'public, max-age=300, s-maxage=600');

In this example header, the directives do three things:

  • public — Marks the cache as public. This means that both the browser and the intermediate servers (meaning the CDN for Firebase Hosting) can cache the content.

  • max-age — Tells the browser and the CDN how many seconds that they can cache the content. When the set time expires, the browser and the CDN must revalidate the content with the origin server. In the example header, we're allowing the browser and the CDN to cache the content for five minutes (see s-maxage below for specific controls for CDN caching).

  • s-maxage — Overrides the max-age directive for the CDN-caching only; tells the CDN how many seconds that it can cache the content. When the set time expires, the CDN must revalidate the content with the origin server. In the example header, we're overriding the setting for max-age for the CDN only and allowing the CDN to cache the content for ten minutes.

For max-age and s-maxage, set their values to the longest amount of time that you're comfortable with users receiving stale content. If a page changes every few seconds, use a small time value. However, other types of content can be safely cached for hours, days, or even months.

You can learn more about the Cache-Control header on the Mozilla Developer Network and in Google's web developer documentation.

When is cached content served?

The browser and the CDN cache your content based on:

  • The hostname
  • The path
  • The query string
  • The content of the request headers specified in the Vary header

Vary headers

The Vary header determines which request headers should be used to provide an appropriate response (whether the cached content is valid or if the content should be revalidated with the origin server).

Most of the time, you don't need to worry about the Vary header. Firebase Hosting automatically sets an appropriate Vary header on your response for common situations. This includes making sure that any session cookie or authorization header that you're using is made part of the cache key, which prevents accidental leaks of content.

In some advanced use cases, you might have other headers that you need to affect the cache. When that's the case, you can simply set the Vary header on your response:

res.set('Vary', 'Accept-Encoding, X-My-Custom-Header');

With these settings, two otherwise identical requests with different X-My-Custom-Header headers are cached separately.

Оставить отзыв о...

Текущей странице
Нужна помощь? Обратитесь в службу поддержки.