go - 在非 root 路径中提供文件时出现 404 错误
问题描述
我正在运行这个命令“去运行 webapp/main.go”。原因是应用程序引擎将从根目录调用我的应用程序,因此我将路径更改为从根目录调用文件。我也不介意你是否有 Go 最佳实践技巧。
└── webapp
├── app.yaml
├── assets
│ ├── css
│ │ └── index.css
│ └── img
├── main.go
├── main_test.go
└── templates
└── index.html
对如此微不足道的事情怎么会出错感到困惑。localhost:8080/css/index.css 工作正常。我还有另一个处理函数来服务 localhost:8080/static/css/index.css,但我收到 404 错误。当我使用命令“go run main.go”并从代码中删除“webapp”时,一切都很顺利。尽管如此,它如何与 / 而不是 /static/ 一起工作。从这个https://stackoverflow.com/a/47997908/6828897答案中可以看出,它应该将 ./webapp/assets/static 作为目录。我也尝试过 http.StripPrefix 但也没有运气。
package main
import (
"flag"
"log"
"net/http"
"os"
"path/filepath"
"sync"
"text/template"
)
type templateHandler struct {
once sync.Once
filename string
templ *template.Template
}
// ServeHTTP handles the HTTP request.
func (t *templateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
t.once.Do(func() {
t.templ = template.Must(template.ParseFiles(filepath.Join("webapp", "templates", t.filename)))
})
if err := t.templ.Execute(w, r); err != nil {
log.Printf("Error executing template: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
}
func main() {
dir, err := os.Getwd()
if err != nil {
log.Printf(err.Error())
}
log.Printf("dir: %s", dir)
// command flags
var addr = flag.String("addr", ":8080", "The addr of the application.")
flag.Parse()
// env variables
envPort := os.Getenv("PORT")
if envPort != "" {
envPort = ":" + envPort
addr = &envPort
}
fs := http.FileServer(http.Dir("./webapp/assets"))
http.Handle("/static/", fs)
log.Printf("Listening on port %s", *addr)
// http.Handle("/", &templateHandler{filename: "index.html"})
if err := http.ListenAndServe(*addr, fs); err != nil {
log.Fatal(err)
}
}
解决方案
“它如何与 / 而不是 /static/ 一起工作”
因为您fs
直接传递给ListenAndServe
,这意味着DefaultServeMux
使用的http.Handle("/static/", fs)
被忽略/覆盖。
Handle在 DefaultServeMux 中为给定模式注册处理程序。ServeMux 的文档解释了模式是如何匹配的。
ListenAndServe 侦听 TCP 网络地址 addr,然后使用处理程序调用 Serve 以处理传入连接上的请求。接受的连接配置为启用 TCP 保持连接。
处理程序通常为 nil,在这种情况下使用 DefaultServeMux。
ListenAndServe 总是返回一个非零错误。
所以一般来说你应该做的是这样的:
fs := http.FileServer(http.Dir("./webapp/assets"))
// register fs for "/static/" in DefaultServeMux
http.Handle("/static/", fs)
// start listening at addr and serve incoming requests
// using DefaultServeMux as the router (because nil).
if err := http.ListenAndServe(*addr, nil); err != nil {
log.Fatal(err)
}
如果您的设置中存在其他问题,则您的应用程序可能无法立即按预期运行,但是此更改肯定是更接近该目标的必要条件。
推荐阅读
- ios - 网络运行后获取小区计数
- ios - 如何在缩放事件(iOS)上触发图像 CSS @media?
- android - System.err:javax.net.ssl.SSLPeerUnverifiedException:主机名 XXX 即使在添加网络安全配置后也未验证
- azure - 无法在 Azure Devops 服务中获取 TFS 用户权利
- r - 如何从R中的密度范围内选择数据
- r - 变量名列表的非标准评估
- python - python中A1符号单元格值的参数化
- spring-data-jpa - 我正在尝试将“spring-data-jpa-datatables”作为 maven 依赖项引入我的项目,但是在启动服务器时遇到了其他几个错误
- c# - 在继续之前检查前两个字符的 return 语句
- c# - 如何在 WPF 视图中获取无效值