传送静态文件

除了处理动态请求之外,应用通常还需要传送静态文件(如 JavaScript、图片和 CSS)。柔性环境中的应用可以通过 Google Cloud 选项(如 Cloud Storage)传送静态文件,直接传送或使用第三方内容分发网络 (CDN)。

从 Cloud Storage 传送文件

Cloud Storage 可为动态 Web 应用托管静态资源。与直接从应用传送内容相比,使用 Cloud Storage 进行传送可为您带来以下好处:

  • Cloud Storage 实际起到内容分发网络的作用。这不需要任何特殊配置,因为默认情况下,任何可公开读取的对象都会在全球 Cloud Storage 网络中进行缓存。
  • 将传送静态资源的工作转交给 Cloud Storage 处理,应用本身的负载将降低。根据您拥有的静态资源数量以及访问频率,这有可能大幅度降低应用的运行费用。
  • 访问 Cloud Storage 内容的带宽费用通常较低。

您可以使用 gsutil 命令行工具Cloud Storage API 将资源上传到 Cloud Storage。

Google Cloud 客户端库为 Cloud Storage 提供了惯用的客户端,用于在 App Engine 应用中使用 Cloud Storage 存储和检索数据。

从 Cloud Storage 存储分区传送文件的示例

这个简单的示例创建了一个 Cloud Storage 存储分区,并使用 Google Cloud CLI 上传静态资源:

  1. 创建存储分区。通常以项目 ID 命名存储分区(并非必需)。存储分区名称必须保持全局唯一。

    gsutil mb gs://<your-bucket-name>
    
  2. 设置 ACL,授予对存储分区中内容的读取访问权限。

    gsutil defacl set public-read gs://<your-bucket-name>
    
  3. 将内容上传到存储分区。rsync 命令通常是上传和更新资源最快速、最便捷的方法。此外,您也可以使用 cp

    gsutil -m rsync -r ./static gs://<your-bucket-name>/static
    

现在,您可以通过 https://storage.googleapis.com/<your-bucket-name>/static/... 访问静态资源了。

如需详细了解如何使用 Cloud Storage 传送静态资源(包括如何从自定义域名进行传送),请参阅如何托管静态网站

从其他 Google Cloud 服务传送文件

您还可以选择使用 Cloud CDN 或其他 Google Cloud 存储服务。

直接从您的应用传送文件

从应用传送文件通常较为简单,但应注意这种方式存在以下两个弊端:

  • 针对静态文件的请求会使用本可用于动态请求的资源。
  • 从应用传送文件可能会导致响应延迟(具体取决于您的配置),还可能影响系统何时创建新实例来处理负载。

通过应用传送静态文件的示例

Go

以下示例演示了如何使用 Go 运行时版本 1.15 及更早版本和 1.18 及更高版本的应用传送静态文件。请注意,您必须更新 app.yaml 才能使用新版本。如需详细了解如何使用新运行时,请参阅 Go 运行时

您可以使用标准 http.FileServerhttp.ServeFile 直接通过应用传送文件。

v1.18 及更高版本


// Package static demonstrates a static file handler for App Engine flexible environment.
package main

import (
	"fmt"
	"net/http"

	"google.golang.org/appengine"
)

func main() {
	// Serve static files from "static" directory.
	http.Handle("/static/", http.FileServer(http.Dir(".")))

	http.HandleFunc("/", homepageHandler)
	appengine.Main()
}

const homepage = `<!doctype html>
<html>
<head>
  <title>Static Files</title>
  <link rel="stylesheet" type="text/css" href="/static/main.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>`

func homepageHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, homepage)
}

v1.15 及更低版本


// Package static demonstrates a static file handler for App Engine flexible environment.
package main

import (
	"fmt"
	"net/http"

	"google.golang.org/appengine"
)

func main() {
	// Serve static files from "static" directory.
	http.Handle("/static/", http.FileServer(http.Dir(".")))

	http.HandleFunc("/", homepageHandler)
	appengine.Main()
}

const homepage = `<!doctype html>
<html>
<head>
  <title>Static Files</title>
  <link rel="stylesheet" type="text/css" href="/static/main.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>`

func homepageHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, homepage)
}

Java

以下示例演示了如何通过适用于 Java 运行时版本 8 和 11/17 的应用传送静态文件。请注意,您必须更新 app.yaml 才能使用新版本。如需详细了解如何使用新运行时,请参阅 Java 运行时

Java 运行时的 Servlet 容器将使用应用的部署描述符web.xml 文件)将网址(包括静态资源)映射到 Servlet。如果未指定 web.xml,则使用默认值,将所有内容映射到默认 servlet。

在此示例中,./src/main/webapp/index.html 表示 /stylesheets/styles.css 提供的样式表。

版本 11/17

<!doctype html>
<html>
<head>
<title>Static Files</title>
<link rel="stylesheet" type="text/css" href="/stylesheets/styles.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>

版本 8

<!doctype html>
<html>
<head>
<title>Static Files</title>
<link rel="stylesheet" type="text/css" href="/stylesheets/styles.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>

styles.css 文件位于 ./src/main/webapp/stylesheets/styles.css

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

您可以在 web.xml 文件中明确配置静态文件的处理方式。例如,如果希望映射以 .jpg 为扩展名的所有文件的请求:

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.jpg</url-pattern>
</servlet-mapping>

如果您使用网络框架,例如 Play,则需要参考有关静态资源的框架文档。

Node.js

以下示例演示了如何使用 Node.js 运行时版本 16 及更低版本和版本 18 及更高版本的应用传送静态文件。请注意,您必须更新 app.yaml 才能使用新版本。如需详细了解如何使用新运行时,请参阅 Node.js 运行时

大多数 Web 框架都支持传送静态文件。在此示例中,应用利用 express.static 中间件,从 ./public 目录向 /static 网址传送文件。

'use strict';

const express = require('express');
const app = express();

app.set('view engine', 'pug');

// Use the built-in express middleware for serving static files from './public'
app.use('/static', express.static('public'));

app.get('/', (req, res) => {
  res.render('index');
});

// Start the server
const PORT = parseInt(process.env.PORT) || 8080;
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}`);
  console.log('Press Ctrl+C to quit.');
});

视图指代 /static/main.css

doctype html
html(lang="en")
  head
    title Static Files
    meta(charset='utf-8')
    link(rel="stylesheet", href="/static/main.css")
  body
    p This is a static file serving example.

样式表位于 ./public/css,从 /static/main.css 传送。

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

HapiKoaSails 等其他 Node.js 框架通常支持直接从应用传送静态文件。如需详细了解如何配置和使用静态内容,请参阅相关文档。

PHP

PHP 运行时运行 nginx 来处理应用,其配置为传送项目目录中的静态文件。您必须通过在 app.yaml 文件中指定 document_root 来声明文档的根目录:

runtime: php
env: flex

runtime_config:
  document_root: web

Python

以下示例演示了对于 Python 3.7 版及更早版本运行时,如何通过应用传送静态文件。对于 Python 3.8 版及更高版本,请参阅 Python 运行时,详细了解如何使用新版本。

大多数 Web 框架都支持传送静态文件。在此示例中,应用使用 Flask 的内置功能通过 /static 网址传送 ./static 目录中的文件。

此应用包含一个渲染模板的视图。Flask 会自动传送 ./static 目录中的所有内容,而无需额外配置。

import logging

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def hello():
    """Renders and serves a static HTML template page.

    Returns:
        A string containing the rendered HTML page.
    """
    return render_template("index.html")

@app.errorhandler(500)
def server_error(e):
    """Serves a formatted message on-error.

    Returns:
        The error message and a code 500 status.
    """
    logging.exception("An error occurred during a request.")
    return (
        f"An internal error occurred: <pre>{e}</pre><br>See logs for full stacktrace.",
        500,
    )

if __name__ == "__main__":
    # This is used when running locally. Gunicorn is used to run the
    # application on Google App Engine. See entrypoint in app.yaml.
    app.run(host="127.0.0.1", port=8080, debug=True)

该视图渲染的模板包含一个位于 /static/main.css 的样式表。

<!doctype html>
<html>
<head>
  <title>Static Files</title>
  <!--
  Flask automatically makes files in the 'static' directory available via
  '/static'.
  -->
  <link rel="stylesheet" type="text/css" href="/static/main.css">
</head>
<body>
  <p>This is a static file serving example.</p>
</body>
</html>

样式表位于 ./static/main.css

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

DjangoPyramidBottle 等其他 Python 框架通常支持直接从应用传送静态文件。如需详细了解如何配置和使用静态内容,请参阅相应文档。

Ruby

大多数 Web 框架均支持传送静态文件。 以下示例演示了对于 Ruby 运行时 3.1 版及更低版本和 3.2 版,如何使用应用传送静态文件。请注意,您必须更新 app.yaml 文件才能使用新版本。如需详细了解如何使用新版运行时,请参阅 Ruby 运行时

Sinatra

Sinatra 网络框架默认从 ./public 目录传送文件。此应用包含一个指向 /application.css 的视图。

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

样式表位于 ./public/application.css,从 /application.css 传送。

Ruby on Rails

Ruby on Rails网络框架默认从 ./public 目录传送文件。Rails 资源流水线也可以生成静态 JavaScript 和 CSS 文件。

这些示例应用包含一个布局视图,其中包含所有应用样式表:

3.2 版

doctype html
html
  head
    title Serving Static Files
    link rel="stylesheet" href="/application.css"
    script src="/application.js"
  body
    p This is a static file serving example.

3.1 版及更低版本

doctype html
html
  head
    title Serving Static Files
    = stylesheet_link_tag "application", media: "all"
    = javascript_include_tag "application"
    = csrf_meta_tags
  body
    = yield

3.2 版

样式表本身是位于 ./public/application.css.css 文件。

body {
  font-family: Verdana, Helvetica, sans-serif;
  background-color: #CCCCFF;
}

3.1 版及更低版本

样式表本身是位于 ./app/assets/stylesheets/main.css.sassSass 文件。

body
  font-family: Verdana, Helvetica, sans-serif
  background-color: #CCCCFF

默认情况下,Rails 应用在生产环境中运行时不会生成或传送静态资源。

Ruby 运行时会在部署期间执行 rake assets:precompile 来生成静态资源,并设置 RAILS_SERVE_STATIC_FILES 环境变量以在生产环境中启用静态文件传送。

.NET

以下示例演示了对于 .NET 运行时 3.1 版及更低版本和版本 6 及更高版本,如何传送静态文件。请注意,您必须更新 app.yaml 文件才能使用新版本。如需详细了解如何使用新版运行时,请参阅 .NET 运行时

版本 6 及更高版本

<html>
<head>
    <meta charset="utf-8" />
    <title>Hello Static World</title>
</head>
<body>
    <p>This is a static html document.</p>
    <p><img src="trees.jpg" /></p>
</body>
</html>

如需启用传送静态文件的功能,请添加以下代码:

app.UseDefaultFiles();
app.UseStaticFiles();

3.1 版及更低版本

<html>
<head>
    <meta charset="utf-8" />
    <title>Hello Static World</title>
</head>
<body>
    <p>This is a static html document.</p>
    <p><img src="trees.jpg" /></p>
</body>
</html>

如需启用传送静态文件的功能,请添加以下代码:

app.UseDefaultFiles();
app.UseStaticFiles();

从第三方内容分发网络进行传送

您可以使用任何外部第三方 CDN 传送静态文件并缓存动态请求,但您的应用可能会遇到延迟和费用增加的情况。

为了提升性能,您应该使用支持 CDN Interconnect 的第三方 CDN。