Golang使用http.FileSystem和http.Handle实现字符串映射的服务

Golang使用http.FileSystem和http.Handle实现字符串映射的服务 我刚接触Go语言,正在尝试学习如何在不使用第三方库/包的情况下构建一个简单的Web应用程序。

参考这篇文章这段代码作为指导,我拼凑出了以下代码:

func main() {
    fmt.Println("hello world")
}

这段代码可以正常编译(在本地环境,不是在Go Playground上),但除了返回404页面未找到之外,实际上没有产生任何结果…

我想要实现的是在应用程序中创建一个包,允许我构建一个映射,将一些静态内容(如CSS和JS)嵌入其中,然后使用http.Handle提供服务——而不使用像go-bindata、rice或其他任何第三方工具。

任何帮助都将不胜感激…


更多关于Golang使用http.FileSystem和http.Handle实现字符串映射的服务的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

问题已解决;

原来 index.html 无法正常工作的原因是浏览器将其解析为 “/”,通过在文件名前添加斜杠后问题得到了解决。

请参阅:我在 Stack Overflow 上的帖子,用户 ‘Gavin’ 和 ‘YongHao Hu’ 非常热心地提供了帮助。

更多关于Golang使用http.FileSystem和http.Handle实现字符串映射的服务的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要实现使用内置的http.FileSystemhttp.Handle来提供内存中的字符串映射服务,您需要创建一个自定义的文件系统实现。以下是完整的解决方案:

package main

import (
    "errors"
    "io"
    "io/fs"
    "net/http"
    "os"
    "time"
)

// 自定义文件系统实现
type inMemoryFS struct {
    files map[string]*inMemoryFile
}

type inMemoryFile struct {
    name     string
    data     []byte
    modTime  time.Time
    isDir    bool
    children []*inMemoryFile
}

func (f *inMemoryFile) Read(p []byte) (int, error) {
    if f.isDir {
        return 0, errors.New("cannot read directory")
    }
    if len(p) == 0 {
        return 0, nil
    }
    if len(f.data) == 0 {
        return 0, io.EOF
    }
    n := copy(p, f.data)
    return n, io.EOF
}

func (f *inMemoryFile) Close() error {
    return nil
}

func (f *inMemoryFile) Readdir(count int) ([]fs.FileInfo, error) {
    if !f.isDir {
        return nil, errors.New("not a directory")
    }
    var infos []fs.FileInfo
    for _, child := range f.children {
        infos = append(infos, child)
    }
    return infos, nil
}

func (f *inMemoryFile) Stat() (fs.FileInfo, error) {
    return f, nil
}

// 实现fs.FileInfo接口
func (f *inMemoryFile) Name() string       { return f.name }
func (f *inMemoryFile) Size() int64        { return int64(len(f.data)) }
func (f *inMemoryFile) Mode() fs.FileMode {
    if f.isDir {
        return fs.ModeDir | 0755
    }
    return 0644
}
func (f *inMemoryFile) ModTime() time.Time { return f.modTime }
func (f *inMemoryFile) IsDir() bool        { return f.isDir }
func (f *inMemoryFile) Sys() interface{}   { return nil }

// 实现http.FileSystem接口
func (fs *inMemoryFS) Open(name string) (http.File, error) {
    if file, exists := fs.files[name]; exists {
        return file, nil
    }
    return nil, os.ErrNotExist
}

// 创建内存文件系统
func NewInMemoryFS() *inMemoryFS {
    return &inMemoryFS{
        files: make(map[string]*inMemoryFile),
    }
}

// 添加文件到内存文件系统
func (fs *inMemoryFS) AddFile(path string, content string) {
    fs.files[path] = &inMemoryFile{
        name:    path,
        data:    []byte(content),
        modTime: time.Now(),
        isDir:   false,
    }
}

// 添加目录到内存文件系统
func (fs *inMemoryFS) AddDirectory(path string) {
    fs.files[path] = &inMemoryFile{
        name:    path,
        modTime: time.Now(),
        isDir:   true,
    }
}

func main() {
    // 创建内存文件系统
    memFS := NewInMemoryFS()
    
    // 添加静态文件内容
    memFS.AddFile("/style.css", `
        body { 
            font-family: Arial, sans-serif; 
            margin: 20px;
            background-color: #f0f0f0;
        }
        h1 { color: #333; }
    `)
    
    memFS.AddFile("/script.js", `
        console.log("Hello from embedded JavaScript!");
        document.addEventListener('DOMContentLoaded', function() {
            console.log("Page loaded");
        });
    `)
    
    memFS.AddFile("/index.html", `
        <!DOCTYPE html>
        <html>
        <head>
            <title>Embedded Web App</title>
            <link rel="stylesheet" href="/style.css">
        </head>
        <body>
            <h1>Hello from Embedded Go Web Server!</h1>
            <p>This content is served from memory.</p>
            <script src="/script.js"></script>
        </body>
        </html>
    `)
    
    // 注册文件系统处理器
    http.Handle("/", http.FileServer(memFS))
    
    // 启动服务器
    fmt.Println("Server starting on :8080...")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        fmt.Printf("Server error: %v\n", err)
    }
}

这个实现提供了以下功能:

  1. 自定义文件系统inMemoryFS 实现了 http.FileSystem 接口
  2. 文件支持:可以存储和提供文本文件内容
  3. 目录支持:支持目录结构(虽然示例中未展示完整目录遍历)
  4. 标准接口:完全兼容 http.FileServer

当您访问 http://localhost:8080/index.html 时,服务器会从内存中提供嵌入的HTML文件,该文件又会加载同样嵌入的CSS和JavaScript文件。

您可以根据需要扩展这个基础实现,添加更多文件类型、目录遍历功能或缓存机制。

回到顶部