Có một số cách không tốn kém để lưu trữ một trang web tĩnh được tạo bằng trình tạo trang web tĩnh như Jekyll, Hugo hoặc Pelican: Toàn bộ blog này được tạo tĩnh bằng Jekyll. Tuy nhiên, tôi không thể sử dụng bất kỳ tùy chọn nào ở trên, bởi vì, trong suốt thời gian tồn tại của blogâÃÂànày, tôi đã thay đổi tên miền, thay đổi lược đồ URL và đổi tên bài đăng, đồng thời tôi muốn duy trì tất cả các URL cũ Tôi đã lưu trữ blog này bằng Apache và gần đây hơn là nginx trên một máy ảo duy nhất và các tính năng chuyển hướng của một trong hai phần mềm đều hoạt động tốt, nhưng tôi đã sẵn sàng lưu trữ nó ở một nơi mới và khác biệt Bài đăng trước mô tả cách tôi chuyển hướng URL từ miền cũ sang miền mới bằng Google App Engine và Python, nhưng bây giờ tôi cần một cách để phân phát nội dung tĩnh **và** URL chuyển hướng từ cùng một tên miền. Chính yêu cầu chuyển hướng tên miền đó là lý do tại sao tôi không thể đơn giản sử dụng tính năng chỉ nội dung tĩnh của Google App EngineâÃÂà(được liên kết trong danh sách ở trên). Tuy nhiên, tôi có thể sử dụng Google App Engine kết hợp với một ứng dụng Golang đơn giản để phục vụ cả nội dung tĩnh **và** chuyển hướng cùng tên miền ## Tại sao Máy ứng dụng của Google? Trước khi bạn đi sâu vào phần còn lại của bài đăng, có lẽ bạn đang tự hỏi, tại sao lại lưu trữ một blog trên Google App Engine? Đây là lý do của tôi tại sao: - Nếu lưu lượng truy cập của bạn phù hợp với bậc miễn phí của App EngineâÃÂàtrong 28 giờ phiên bản và 1 GB lưu lượng truy cập ra mỗi ngày, thì việc lưu trữ blog trên thực tế là miễn phí - Đẩy các bản cập nhật được thực hiện bằng một lệnh - Ghi nhật ký và giám sát được tích hợp bằng Stackdriver - Tự động tăng giảm tỷ lệ dựa trên các mẫu lưu lượng truy cập - Với một vài cú nhấp chuột, nhật ký web có thể dễ dàng được chuyển sang một thứ gì đó như BigQuery để lưu trữ lâu dài và phân tích đặc biệt - Chứng chỉ SSL được quản lý bằng LetâÃÂÃÂs Encrypt ## Điều kiện tiên quyết Bài đăng này giả định như sau: - Bạn đã quen thuộc với Google Cloud Platform (GCP) và đã tạo Dự án GCP - Bạn đã cài đặt Google Cloud SDK - Bạn đã xác thực gcloudcommand đối với Tài khoản Google của bạn Tạo dự án GCP Nếu bạn chưa tạo một **Dự án GCP thực hiện theo các bước sau: - Mở trình duyệt web và tạo hoặc đăng nhập vào Tài khoản Google - Điều hướng đến Bảng điều khiển GCP - Nếu đây là Dự án GCP đầu tiên của bạn, bạn sẽ được nhắc tạo Dự án GCP. Mỗi Tài khoản Google nhận được tín dụng $300 để sử dụng trong vòng 12 tháng đối với GCP. Bạn được yêu cầu nhập thẻ tín dụng để tạo Dự án GCP, nhưng nó sẽ không bị tính phí cho đến khi sử dụng hết khoản tín dụng $300 hoặc hết hạn 12 tháng - Nếu đây là Dự án GCP mới, bạn sẽ cần bật API Công cụ điện toán bằng cách điều hướng đến phần Công cụ điện toán của Bảng điều khiển GCP và đợi quá trình khởi tạo hoàn tất Cài đặt Google Cloud SDK Nếu bạn chưa cài đặt **Google Cloud SDK làm theo hướng dẫn tại đây Xác thực gcloud Khi bạn đã tạo Dự án GCP và cài đặt Google Cloud SDK, bước cuối cùng là xác thực lệnh gcloud vào Tài khoản Google của bạn. Mở ứng dụng đầu cuối của bạn và chạy lệnh sau: đăng nhập xác thực gcloud Một trang web sẽ mở ra trong trình duyệt web của bạn. Chọn Tài khoản Google của bạn và cấp cho nó quyền truy cập GCP. Sau khi hoàn thành, bạn sẽ được xác thực và sẵn sàng tiếp tục ## Tạo thư mục Tiếp theo, tạo một thư mục ở đâu đó trên máy trạm của bạn để lưu trữ ứng dụng Google App Engine của bạn: mkdir ~/Sites/example.com/app_engine Thay đổi vào thư mục đó: cd ~/Sites/example.com/app_engine Phần còn lại của bài đăng này sẽ cho rằng bạn đang làm việc bên trong thư mục này Ngoài ra, hãy tạo một thư mục bên trong **app_engine** thư mục được gọi là **static mkdir ~/Sites/example.com/app_engine/static Bạn sẽ xem lại thư mục này sau ## Tạo app.yaml Google App Engine thường yêu cầu hai tệp: **app.yaml** và một **tệp ứng dụng** được viết bằng Python, Golang, Java hoặc PHP - trong trường hợp này, nó sẽ là Golang. **app.yaml** cung cấp cấu hình cần thiết để chạy ứng dụng của bạn. Có rất nhiều tham số khác nhau có thể tồn tại trong **app.yaml. Các tham số đó có thể khác nhau tùy theo ngôn ngữ lập trình được sử dụng. Đối với bài đăng này, Golang sẽ được sử dụng và bạn có thể tìm thấy tất cả các tham số Golang có sẵn tại đây tạo tập tin **app.yaml** với nội dung như sau: thời gian chạy: đi api_version: trình xử lý go1: - url:script: _go_app bảo mật: luôn chuyển hướng_http_response_code: 301 Thông báo rằng **an toàn: luôn luôn** đã được thiết lập. Điều này có nghĩa là ứng dụng Golang sẽ luôn được cung cấp qua HTTPS. Nếu người dùng cuối điều hướng đến ứng dụng web qua HTTP, thì theo mặc định, họ sẽ được chuyển hướng 302 sang phiên bản HTTPS. Đây là lý do tại sao **redirect_http_response_code: 301** cũng đã được đặt. Tôi luôn muốn ứng dụng web được cung cấp qua HTTPS và tôi không muốn các công cụ tìm kiếm hiểu chuyển hướng từ HTTP sang HTTPS là chuyển hướng tạm thời; nó là một chuyển hướng vĩnh viễn Nếu bạn có nội dung tĩnh và bạn có thể có, thì cách tốt nhất là thông báo cho App Engine về điều này và để nó phục vụ các nội dung đó từ bộ lưu trữ đối tượng thay vì từ ứng dụng của bạn. Làm điều này là dễ dàng và cũng được thực hiện thông qua **app.yaml** tập tin Ví dụ: nếu bạn có tệp favicon, thư mục CSS, thư mục Javascript và thư mục hình ảnh, hãy sử dụng như sau **app.yaml** tập tin: thời gian chạy: go api_version: go1 handlers: - url: /favicon.png$ static_files: static/favicon.png upload: 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 bảo mật: luôn chuyển hướng_http_response_code: 301 ## Tạo main.go Tiếp theo, bạn cần tệp ứng dụng Golang Để đoạn mã sau đáp ứng nhu cầu của bạn, hãy tạo tệp **main.go sao chép và dán mã bên dưới và thực hiện các sửa đổi sau: - Bên trong biến miền, hãy thay đổi giá trị để khớp với tên miền của bạn với đúng giao thức HTTP - Bên trong bản đồ url, hãy thay thế tất cả các cặp giá trị khóa để khớp với chuyển hướng bạn cần tại chỗ. Thay thế từng khóa bằng phần đường dẫn ( /example-post-1.htmlthay vì httpsexample.com/example-post-1.html) của URL cũ của miền hiện tại mà bạn muốn cố sống đi. Sau đó, thay thế từng giá trị bằng phần đường dẫn của URL mới của tên miền hiện tại mà bạn muốn chuyển hướng đến Tất cả các chuyển hướng sẽ là chuyển hướng 301. Điều này có thể được sửa đổi bằng cách thay đổi **301** trong mã bên dưới thành mã trạng thái chuyển hướng HTTP khác, chẳng hạn như **302** nhập gói chính ( "net/http""os""strings") func init() { http.HandleFunc handler) } func handler(w http.ResponseWriter, r *http.Request) { // Đúng (ok) nếu có yêu cầu đường dẫn nằm trong bản đồ url nếu giá trị, ok := urls[r.URL.Path]; ok { value = domain + value http.Redirect(w, r, value, 301) } other { path := "static/"+ r.URL.Path // Trả về 403 nếu yêu cầu HTTP đến một thư mục tồn tại và không không chứa tệp index.html nếu 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 Bị cấm

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