Golang文件解析遇到无效文件描述符错误怎么解决

Golang文件解析遇到无效文件描述符错误怎么解决 大家好,

我正在尝试使用 Go 的模板语法创建一个基础的 Go 服务器。

以下是项目结构:

  • gohtml ---- index.gohtml ---- about.gohtml
  • templates ---- layout.gohtml
  • server.go

以下是每个文件的代码:

index.gohtml

{{define "page_title"}} Welcome Page {{ end }}

{{define "page_body"}}

<p>Welcome on home page !</p>

{{end}}

about.gohtml

{{define "page_title"}} About Page {{ end }}

{{define "page_body"}}

<p>Welcome on about page !</p>

{{end}}

layout.gohtml

{{define "layout}}

<!DOCTYPE html>

<html>

<head>
    <meta charset="utf-8">
    <title>{{template "page_title"}}</title>
</head>

<body>

 {{template "page_body"}}

 </body>

</html>

{{end}}

server.go

package main

import (
    "net/http"
    "html/template"
    "path/filepath"
    "log"
)

func main(){

// Handle client's requests to templates system

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){

// Manage template's layout path

layout_path := filepath.Join("templates","layout.gohtml")

// Manage *http.request

request_path := filepath.Join("gohtml",filepath.Clean(r.URL.Path))

// Parse layout and client's request files

template_page, err := template.ParseFiles(request_path, layout_path)

if err != nil{

    log.Println("Error : Failed to parse files")

    log.Fatal(err)

}

// Execute template on http.ResponseWriter

template_page.ExecuteTemplate(w, "layout", nil)

})

// Start server
// Error handling OK

log.Fatal(http.ListenAndServe(":8080", nil))

}

当我运行 server.go 文件时,我得到:

2020/03/31 11:44:58 Error : Failed to parse files
2020/03/31 11:44:58 read gohtml: Bad file descriptor
exit status 1

提前感谢您的帮助。


更多关于Golang文件解析遇到无效文件描述符错误怎么解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

好的,各位,

我自己找到了解决方案,哈哈!

显然,template.Parsefiles 的工作方式是这样的:

template_page, err := template.Parsefiles(layout_path, request_path)

而不是:

template_page, err := template.Parsefiles(request_path, layout_path)

另外,我在 layout.gohtml 文件中漏掉了一个引号:

{{define "layout}}

应该是:

{{define "layout"}}

更多关于Golang文件解析遇到无效文件描述符错误怎么解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个错误是因为 filepath.Clean(r.URL.Path) 在根路径 / 时会返回 .,导致 request_path 变成了 gohtml/.,这是一个无效的文件路径。

主要问题有两个:

  1. 当访问根路径 / 时,r.URL.Path/,经过 filepath.Clean() 处理后变成 .
  2. 没有正确处理默认页面(如 index.gohtml)

以下是修正后的 server.go 代码:

package main

import (
    "html/template"
    "log"
    "net/http"
    "path/filepath"
    "strings"
)

func main() {
    // 预解析布局模板
    layoutPath := filepath.Join("templates", "layout.gohtml")
    layoutTmpl, err := template.ParseFiles(layoutPath)
    if err != nil {
        log.Fatal("Failed to parse layout template:", err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // 获取请求路径并清理
        path := strings.TrimPrefix(r.URL.Path, "/")
        if path == "" {
            path = "index.gohtml"
        } else {
            path = path + ".gohtml"
        }

        // 构建完整文件路径
        requestPath := filepath.Join("gohtml", filepath.Clean(path))

        // 解析内容模板
        contentTmpl, err := template.ParseFiles(requestPath)
        if err != nil {
            http.Error(w, "Page not found", http.StatusNotFound)
            log.Println("Failed to parse content template:", err)
            return
        }

        // 合并布局和内容模板
        tmpl, err := template.Must(layoutTmpl.Clone()).ParseFiles(requestPath)
        if err != nil {
            http.Error(w, "Internal server error", http.StatusInternalServerError)
            log.Println("Failed to clone template:", err)
            return
        }

        // 执行模板
        err = tmpl.ExecuteTemplate(w, "layout", nil)
        if err != nil {
            http.Error(w, "Internal server error", http.StatusInternalServerError)
            log.Println("Failed to execute template:", err)
        }
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

或者使用更简洁的方法,预加载所有模板:

package main

import (
    "html/template"
    "log"
    "net/http"
    "path/filepath"
)

func main() {
    // 预加载所有模板文件
    tmpl, err := template.ParseGlob("templates/*.gohtml")
    if err != nil {
        log.Fatal("Failed to parse layout:", err)
    }

    // 添加 gohtml 目录下的模板
    _, err = tmpl.ParseGlob("gohtml/*.gohtml")
    if err != nil {
        log.Fatal("Failed to parse content templates:", err)
    }

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // 确定要使用的模板
        page := r.URL.Path[1:] // 移除开头的斜杠
        if page == "" {
            page = "index"
        }

        // 检查模板是否存在
        if tmpl.Lookup(page+".gohtml") == nil {
            http.Error(w, "Page not found", http.StatusNotFound)
            return
        }

        // 执行模板
        err := tmpl.ExecuteTemplate(w, "layout", nil)
        if err != nil {
            http.Error(w, "Internal server error", http.StatusInternalServerError)
            log.Println("Failed to execute template:", err)
        }
    })

    log.Fatal(http.ListenAndServe(":8080", nil))
}

还需要修正 layout.gohtml 中的模板定义语法错误:

{{define "layout"}}  <!-- 缺少闭合引号 -->

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{template "page_title" .}}</title>
</head>
<body>
    {{template "page_body" .}}
</body>
</html>

{{end}}

修正后,访问 http://localhost:8080/ 会显示 index.gohtml 的内容,访问 http://localhost:8080/about 会显示 about.gohtml 的内容。

回到顶部