有几种廉价的方法可以托管使用静态网站生成器(如 Jekyll、Hugo 或 Pelican)生成的静态网站: 整个博客是使用 Jekyll 静态生成的。但是,我无法使用上面的任何选项,因为在这个博客的生命周期中,我更改了域名、更改了 URL 方案并重命名了帖子,我想保留所有旧网址 我一直在使用 Apache 和最近在单个虚拟机上使用 nginx 来托管这个博客,这两种软件的重定向功能都可以正常工作,但我已经准备好将它托管在一个新的和不同的地方 上一篇文章描述了我如何使用 Google App Engine 和 Python 将 URL 从旧域重定向到新域,但现在我需要一种方法来提供静态内容 **和** 重定向来自同一域的 URL。同样的域重定向要求就是为什么我不能简单地使用 Google App Engine 的“仅静态内容”功能(链接在上面的列表中)。但是,我可以结合使用 Google App Engine 和一个简单的 Golang 应用程序来提供静态内容 ** 和 ** 相同的域重定向 ## 为什么选择 Google App Engine? 在深入阅读本文的其余部分之前,您可能想知道为什么要在 Google App Engine 上托管博客?以下是我的理由: - 如果您的流量符合 App Engine 的 28 个实例小时免费层和每天 1 GB 的出口流量,则托管博客几乎是免费的 - 推送更新是用一个命令完成的 - 使用 Stackdriver 集成日志记录和监控 - 根据流量模式自动上下缩放 - 只需点击几下,网络日志就可以轻松地推送到 BigQuery 之类的东西,以进行长期存储和临时分析 - 托管 SSL 证书使用 LetâÃÃÃs Encrypt ##先决条件 这篇文章假设如下: - 您熟悉 Google Cloud Platform (GCP) 并已创建 GCP 项目 - 你已经安装了谷歌云 SDK - 你已经验证了 针对您的 Google 帐户的 gcloud 命令 创建 GCP 项目 如果您还没有创建 **GCP 项目遵循以下步骤: - 打开网络浏览器,创建或登录 Google 帐户 - 导航到 GCP 控制台 - 如果这是您的第一个 GCP 项目,系统将提示您创建一个 GCP 项目。每个 Google 帐户都会获得 300 美元的信用额度,可在 12 个月内用于 GCP。您需要输入信用卡才能创建 GCP 项目,但在 300 美元信用额度用完或 12 个月到期之前不会被收取费用 - 如果这是一个新的 GCP 项目,您需要通过导航到 GCP 控制台的计算引擎部分启用计算引擎 API,并等待初始化完成 安装谷歌云 SDK 如果您还没有安装 **谷歌云 SDK 按照此处的说明进行操作 验证 gcloud 创建 GCP 项目并安装 Google Cloud SDK 后,最后一步是验证 gcloud 命令到您的 Google 帐户。打开终端应用程序并运行以下命令: gcloud 授权登录 网页将在您的网络浏览器中打开。选择您的 Google 帐户并授予其访问 GCP 的权限。完成后,您将通过身份验证并准备好继续前进 ## 创建一个目录 接下来,在您工作站的某个位置创建一个目录来存储您的 Google App Engine 应用程序: mkdir ~/Sites/example.com/app_engine 更改到该目录: cd ~/Sites/example.com/app_engine 这篇文章的其余部分将假设您正在该目录中工作 另外,在里面创建一个目录 **app_engine** 目录名为 **static mkdir ~/Sites/example.com/app_engine/static 稍后您将重新访问此目录 ## 创建 app.yaml Google App Engine 通常需要两个文件: **app.yaml** 和一个用 Python、Golang、Java 或 PHP 编写的**应用程序文件**——在本例中,它将是 Golang。 **app.yaml** 提供运行应用程序所需的配置。 **app.yaml 中可以存在许多不同的参数,这些参数可能因使用的编程语言而异。对于这篇文章,将使用 Golang,您可以在此处找到所有可用的 Golang 参数 创建文件 **app.yaml** 包含以下内容: 运行时:转到 api_version:go1 处理程序:- url:脚本:_go_app 安全:始终 redirect_http_response_code:301 请注意 **安全:始终**已设置。这意味着 Golang 应用程序将始终通过 HTTPS 提供服务。如果最终用户通过 HTTP 导航到 Web 应用程序,他们将默认被 302 重定向到 HTTPS 版本。这就是为什么 **redirect_http_response_code: 301** 也被设置了。我一直希望 Web 应用程序通过 HTTPS 提供服务,我不希望搜索引擎将从 HTTP 到 HTTPS 的重定向解释为临时重定向;这是一个永久重定向 如果您有静态资产(您可能有),最好将此通知 App Engine 并让它从对象存储而不是您的应用程序中为这些资产提供服务。这样做很容易,也可以通过 **app.yaml** 文件 例如,如果您有一个图标文件、一个 CSS 目录、一个 Javascript 目录和一个图像目录,请使用以下命令 **app.yaml** 文件: 运行时:转到 api_version:go1 处理程序:- url:/favicon.png $ static_files:static/favicon.png 上传:static/favicon.png - url:/css static_dir:static/css - url:/js static_dir:static/js - url: /images static_dir: static/images - url:script: _go_app secure: always redirect_http_response_code: 301 ## 创建 main.go 接下来需要Golang应用文件 为以下代码满足您的需要,创建文件 **main.go 复制粘贴下面的代码,做如下修改: - 在里面 域变量,更改值以使用正确的 HTTP 协议匹配您的域名 - 在里面 urlsmap,替换所有键值对以匹配您需要的重定向。仅将每个键替换为当前域的路径部分(/example-post-1.html 而不是 httpsexample.com/example-post-1.html)- 您想要的旧 URL活着。然后将每个值替换为您要重定向到的当前域的新 URL 的路径部分 所有重定向都是 301 重定向。这可以通过更改来修改 下面代码中的 **301** 到不同的 HTTP 重定向状态代码,例如 **302** package main import ( "net/http""os""strings") func init() { http.HandleFunc handler) } func handler(w http.ResponseWriter, r *http.Request) { // True (ok) 如果请求path 在 urls map if value 中,ok := urls[r.URL.Path]; ok { value = domain + value http.Redirect(w, r, value, 301) } else { path := "static/"+ r.URL.Path // 如果 HTTP 请求是针对存在且确实存在的目录,则返回 403不包含 index.html 文件 if f, err := os.Stat(path); err == nil&& f.IsDir() { index := strings.TrimSuffix(path,+ "/index.html"if _, err := os.Open(index); err != nil { w.WriteHeader (403) w.Writebytehtml> 403 禁止

403 Forbidden

return } } // Return custom 404 page if HTTP request is to a non-existent file if _, err := os.Stat(path); os.IsNotExist(err) { w.WriteHeader(404) http.ServeFile(w, r, "static/404.html") return // Withoutreturn, a "404 page not found" string will be displayed at the bottom of your custom 404 page } http.ServeFile(w, r, path) return } } var domain string = "httpsexample.com" var urls = map[string]string{ "/example-post-1.html": "/post/example-post-1.html", "/example-post-2.html": "/post/example-post-2.html", "/example-post-3.html": "/post/example-post-3.html", } ## Generate the Static Content With **app.yaml** and **main.go** saved, the last piece is to generate your static content and store it in the **static** directory you created earlier How you do this entirely depends on what static site generator you are using If you are using Jekyll, you can configure the **destination** parameter in Jekyll’s _ **config.yml** file to save your static content in any directory on your workstation. So, you could set the **destination** parameter to Sites/example.com/app_engine/static and, every time you run jekyll build, the static content will be saved in that directory ## Deploy to App Engine With **app.yaml **main.go and your static content generated, you are ready to deploy your Google App Engine application Assuming gcloud is already pointed at the Google Cloud Project you want to deploy to, verify with gcloud config list project, run the following command: gcloud app deploy The command will output the appspot URL your application will be deployed to and ask if you want to continue. Typically, the appspot URL is **httpsyour-project-id.appspot.com This is also a useful self-check to make sure you are not deploying your application to the wrong Google Cloud Project. If everything looks okay, type **Y** and **Enter** to deploy your application. Depending on how large your static content is, your application should be deployed within about one minute ## Setup DNS At this point, your application is deployed under URL **httpsyour-project-id.appspot.com Unless your website uses that as its domain name, you will probably want to setup a custom domain that uses your actual current domain name The App Engine section of the Google Cloud Console can be used to do this. Go here and follow the instructions to configure your custom domain Once that is complete and DNS has had time to propagate, you should be able to navigate in your web browser to one of your current domain’s old URLs, for example **httpsexample.com/example-post-1.html and have it redirect to your current domain’s new URLs, for example **httpsexample.com/post/example-post-1.html** ## Pushing Updates To push updates, make the necessary changes in your static site’s source directory, regenerate the static content, and redeploy to Google App Engine by changing into the Sites/example.com/app_engine** directory and running gcloud app deploy ## References - A Surprising Feature of Golang that Colored Me Impressed - How to check if a map contains a key in go? - Disable directory listing with http.FileServer - 3 Ways to Disable http.FileServer Directory Listings - Handling HTTP Request Errors in GO - HTTP and Error management in Go - please add ability to set custom 404 notFoundHandler for http.FileServer