在 Go (Golang) 中使用 http.filesystem 在没有第三方库的情况下提供字符串映射
Serving a map of strings without 3rd party libraries using http.filesystem in Go (Golang)
我刚开始使用 Go,正在尝试学习如何在不使用第 3 方库/包的情况下构建一个简单的 Web 应用程序。
使用 this post and this code 作为指导,我已经破解了以下内容:
package main
import (
"bytes"
"net/http"
"os"
"path"
"time"
)
type StaticFS map[string]*staticFile
type staticFile struct {
name string
data []byte
fs StaticFS
}
func LoadAsset(name string, data string, fs StaticFS) *staticFile {
return &staticFile{name: name,
data: []byte(data),
fs: fs}
}
func (fs StaticFS) prepare(name string) (*staticFile, error) {
f, present := fs[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
return f, nil
}
func (fs StaticFS) Open(name string) (http.File, error) {
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}
func (f *staticFile) File() (http.File, error) {
type httpFile struct {
*bytes.Reader
*staticFile
}
return &httpFile{
Reader: bytes.NewReader(f.data),
staticFile: f,
}, nil
}
//implement the rest of os.FileInfo
func (f *staticFile) Close() error {
return nil
}
func (f *staticFile) Stat() (os.FileInfo, error) {
return f, nil
}
func (f *staticFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
func (f *staticFile) Name() string {
return f.name
}
func (f *staticFile) Size() int64 {
return int64(len(f.data))
}
func (f *staticFile) Mode() os.FileMode {
return 0
}
func (f *staticFile) ModTime() time.Time {
return time.Time{}
}
func (f *staticFile) IsDir() bool {
return false
}
func (f *staticFile) Sys() interface{} {
return f
}
func main() {
const HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<p>Hello World</p>
</main>
</body>
</html>
`
const CSS = `
p {
color:red;
text-align:center;
}
`
ASSETS := make(StaticFS)
ASSETS["index.html"] = LoadAsset("index.html", HTML, ASSETS)
ASSETS["style.css"] = LoadAsset("style.css", CSS, ASSETS)
http.Handle("/", http.FileServer(ASSETS))
http.ListenAndServe(":8080", nil)
}
编译正常,但除了 404 页面未找到之外实际上没有产生任何结果..
我想要实现的是在我的应用程序中有一个包,允许我制作地图,在其中嵌入一些静态内容,例如 css 和 js,然后使用 http.Handle 提供它- 不使用 go-bindata、rice 或其他任何第三方工具。
任何帮助将不胜感激..
这是我们需要查看的主要代码,它来自关于 http.FileServer
:
的源代码
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
upath := r.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
r.URL.Path = upath
}
serveFile(w, r, f.root, path.Clean(upath), true)
}
// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
const indexPage = "/index.html"
// redirect .../index.html to .../
// can't use Redirect() because that would make the path absolute,
// which would be a problem running under StripPrefix
if strings.HasSuffix(r.URL.Path, indexPage) {
localRedirect(w, r, "./")
return
}
f, err := fs.Open(name)
if err != nil {
msg, code := toHTTPError(err)
Error(w, msg, code)
return
}
defer f.Close()
...
}
在 ServeHTTP
方法中,您将看到对未导出函数的调用。
serveFile(w, r, f.root, path.Clean(upath), true)
其中 upath
是保证以“/”开头的请求的 URL 路径。
在serveFile
中调用fs.Open(name)
,其中fs
是您提供的FileSystem
,name
是我们作为[=22传递的参数=].请注意 path.Clean
已经被调用,因此您不需要在 prepare
方法中调用它。
这里的要点是您存储的 "file names" 前面没有“/”,这表示它们位于文件系统的根目录中。
您可以通过两种不同的方式解决此问题。
1.
ASSETS["/index.html"] = LoadAsset("index.html", HTML, ASSETS)
ASSETS["/style.css"] = LoadAsset("style.css", CSS, ASSETS)
2.
func (fs StaticFS) Open(name string) (http.File, error) {
if strings.HasPrefix(name, "/") {
name = name[1:]
}
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}
我刚开始使用 Go,正在尝试学习如何在不使用第 3 方库/包的情况下构建一个简单的 Web 应用程序。
使用 this post and this code 作为指导,我已经破解了以下内容:
package main
import (
"bytes"
"net/http"
"os"
"path"
"time"
)
type StaticFS map[string]*staticFile
type staticFile struct {
name string
data []byte
fs StaticFS
}
func LoadAsset(name string, data string, fs StaticFS) *staticFile {
return &staticFile{name: name,
data: []byte(data),
fs: fs}
}
func (fs StaticFS) prepare(name string) (*staticFile, error) {
f, present := fs[path.Clean(name)]
if !present {
return nil, os.ErrNotExist
}
return f, nil
}
func (fs StaticFS) Open(name string) (http.File, error) {
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}
func (f *staticFile) File() (http.File, error) {
type httpFile struct {
*bytes.Reader
*staticFile
}
return &httpFile{
Reader: bytes.NewReader(f.data),
staticFile: f,
}, nil
}
//implement the rest of os.FileInfo
func (f *staticFile) Close() error {
return nil
}
func (f *staticFile) Stat() (os.FileInfo, error) {
return f, nil
}
func (f *staticFile) Readdir(count int) ([]os.FileInfo, error) {
return nil, nil
}
func (f *staticFile) Name() string {
return f.name
}
func (f *staticFile) Size() int64 {
return int64(len(f.data))
}
func (f *staticFile) Mode() os.FileMode {
return 0
}
func (f *staticFile) ModTime() time.Time {
return time.Time{}
}
func (f *staticFile) IsDir() bool {
return false
}
func (f *staticFile) Sys() interface{} {
return f
}
func main() {
const HTML = `<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<p>Hello World</p>
</main>
</body>
</html>
`
const CSS = `
p {
color:red;
text-align:center;
}
`
ASSETS := make(StaticFS)
ASSETS["index.html"] = LoadAsset("index.html", HTML, ASSETS)
ASSETS["style.css"] = LoadAsset("style.css", CSS, ASSETS)
http.Handle("/", http.FileServer(ASSETS))
http.ListenAndServe(":8080", nil)
}
编译正常,但除了 404 页面未找到之外实际上没有产生任何结果..
我想要实现的是在我的应用程序中有一个包,允许我制作地图,在其中嵌入一些静态内容,例如 css 和 js,然后使用 http.Handle 提供它- 不使用 go-bindata、rice 或其他任何第三方工具。
任何帮助将不胜感激..
这是我们需要查看的主要代码,它来自关于 http.FileServer
:
func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
upath := r.URL.Path
if !strings.HasPrefix(upath, "/") {
upath = "/" + upath
r.URL.Path = upath
}
serveFile(w, r, f.root, path.Clean(upath), true)
}
// name is '/'-separated, not filepath.Separator.
func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirect bool) {
const indexPage = "/index.html"
// redirect .../index.html to .../
// can't use Redirect() because that would make the path absolute,
// which would be a problem running under StripPrefix
if strings.HasSuffix(r.URL.Path, indexPage) {
localRedirect(w, r, "./")
return
}
f, err := fs.Open(name)
if err != nil {
msg, code := toHTTPError(err)
Error(w, msg, code)
return
}
defer f.Close()
...
}
在 ServeHTTP
方法中,您将看到对未导出函数的调用。
serveFile(w, r, f.root, path.Clean(upath), true)
其中 upath
是保证以“/”开头的请求的 URL 路径。
在serveFile
中调用fs.Open(name)
,其中fs
是您提供的FileSystem
,name
是我们作为[=22传递的参数=].请注意 path.Clean
已经被调用,因此您不需要在 prepare
方法中调用它。
这里的要点是您存储的 "file names" 前面没有“/”,这表示它们位于文件系统的根目录中。
您可以通过两种不同的方式解决此问题。
1.
ASSETS["/index.html"] = LoadAsset("index.html", HTML, ASSETS)
ASSETS["/style.css"] = LoadAsset("style.css", CSS, ASSETS)
2.
func (fs StaticFS) Open(name string) (http.File, error) {
if strings.HasPrefix(name, "/") {
name = name[1:]
}
f, err := fs.prepare(name)
if err != nil {
return nil, err
}
return f.File()
}