为什么我的脚本读取在我的 HTML 中链接的文件,而在 GoLang 中使用

我有一个 GoLang 脚本,用于根据浏览器中的输入查询动态构建网页,如下所示http://localhost:8000/blog/post#,该post#部分用于识别要解析到我创建的 HTML 模板中的 JSON 数据文件;例如,如果我把它从我的文件中http://localhost:8000/blog/post1创建一个文件。目前,我的脚本在运行时允许我在浏览器中加载单个页面,然后它退出并在我的终端标准输出日志中显示错误:index.htmlpost1.json


2022/03/18 00:32:02 error: open jsofun.css.json: no such file or directory

exit status 1

这是我当前的脚本:


package main


import (

    "encoding/json"

    "html/template"

    "io/ioutil"

    "log"

    "net/http"

    "os"

)


func blogHandler(w http.ResponseWriter, r *http.Request) {

    blogstr := r.URL.Path[len("/blog/"):]


    blogstr = blogstr + ".json"


    // read the file in locally

    json_file, err := ioutil.ReadFile(blogstr)

    if err != nil {

        log.Fatal("error: ", err)

    }


    // define a data structure

    type BlogPost struct {

        // In order to see these elements later, these fields must be exported

        // this means capitalized naming and the json field identified at the end

        Title       string `json:"title"`

        Timestamp   string `json:"timestamp"`

        Main        string `json:"main"`

        ContentInfo string `json:"content_info"`

    }


    // json data

    var obj BlogPost


    err = json.Unmarshal(json_file, &obj)

    if err != nil {

        log.Fatal("error: ", err)

    }


    tmpl, err := template.ParseFiles("./blogtemplate.html")


    HTMLfile, err := os.Create("index.html")

    if err != nil {

        log.Fatal(err)

    }


    defer HTMLfile.Close()


    tmpl.Execute(HTMLfile, obj)


    http.ServeFile(w, r, "./index.html")

}


func main() {

    http.HandleFunc("/blog/", blogHandler)

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

}

我已经完成了一些基本的调试,并确定问题出在以下几行:


json_file, err := ioutil.ReadFile(blogstr)

    if err != nil {

        log.Fatal("error: ", err)

    }

令我困惑的是为什么 ioutil.ReadFile 也试图读取我的 HTML 中链接的文件?浏览器不应该处理该链接而不是我的处理程序吗?作为参考,这是我jsofun.css链接文件的 HTML;我的控制台输出中引用的错误显示我的脚本jsofun.css.json在调用期间尝试访问此文件ioutil.ReadFile:


慕码人8056858
浏览 77回答 2
2回答

繁星coding

您的 Go 服务器设置为仅提供/blog/路径服务,它通过执行blogHandler. 在您的 Go 服务器中没有其他任何东西被设置为提供诸如 css、js 或图像文件之类的资产。对于这样的事情,您通常需要FileServer在单独的路径上注册一个单独的处理程序。例子:func main() {&nbsp; &nbsp; http.HandleFunc("/blog/", blogHandler)&nbsp; &nbsp; // To serve a directory on disk (/path/to/assets/on/my/computer)&nbsp; &nbsp; // under an alternate URL path (/assets/), use StripPrefix to&nbsp; &nbsp; // modify the request URL's path before the FileServer sees it:&nbsp; &nbsp; http.Handle("/assets/", http.StripPrefix("/assets/",&nbsp; &nbsp; &nbsp; &nbsp; http.FileServer(http.Dir("/path/to/assets/on/my/computer"))))&nbsp; &nbsp; log.Fatal(http.ListenAndServe(":8080", nil))}您需要修复的另一件事是 HTML 中那些资产字段的链接,它们应该是绝对的,而不是相对的。...<link rel="stylesheet" href="/assets/jsofun.css"></style>...<script src="/assets/jsofun.js">以上当然只有在资产位于/path/to/assets/on/my/computer目录中时才有效,例如/path/to/assets/on/my/computer├── jsofun.css└── jsofun.js您blogHandler不必要地为每个请求创建一个新文件而不删除它,这有可能很快将您的磁盘填满到其最大容量。要提供模板,您不需要创建新文件,而是可以直接将模板执行到http.ResposeWriter. 还建议只解析一次模板,尤其是在生产代码中,以避免不必要的资源浪费:type BlogPost struct {&nbsp; &nbsp; Title&nbsp; &nbsp; &nbsp; &nbsp;string `json:"title"`&nbsp; &nbsp; Timestamp&nbsp; &nbsp;string `json:"timestamp"`&nbsp; &nbsp; Main&nbsp; &nbsp; &nbsp; &nbsp; string `json:"main"`&nbsp; &nbsp; ContentInfo string `json:"content_info"`}var blogTemplate = template.Must(template.ParseFiles("./blogtemplate.html"))func blogHandler(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; blogstr := r.URL.Path[len("/blog/"):] + ".json"&nbsp; &nbsp; f, err := os.Open(blogstr)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; http.Error(w, err.Error(), http.StatusNotFound)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; defer f.Close()&nbsp; &nbsp; var post BlogPost&nbsp; &nbsp; if err := json.NewDecoder(f).Decode(&post); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; http.Error(w, err.Error(), http.StatusInternalServerError)&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp; if err := blogTemplate.Execute(w, post); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Println(err)&nbsp; &nbsp; }}

呼唤远方

让我们研究一下当您请求时会发生什么http://localhost:8000/blog/post#。浏览器请求页面;您的代码成功构建并返回一些html- 这将包括:<link rel="stylesheet" href="./jsofun.css"></style>浏览器接收并处理 HTML;作为该过程的一部分,它要求css上述内容。现在原始请求在文件夹中,/blog/post#因此./jsofun.css变为http://localhost:8000/blog/jsofun.css.当您的 go 应用程序收到此请求blogHandler时将被调用(由于请求路径);它剥离/blog/然后添加.json以获取文件名jsofun.css.json。然后您尝试打开此文件并收到错误消息,因为它不存在。有几种方法可以解决这个问题;更改要使用的模板<link rel="stylesheet" href="/jsofun.css"></style>可能是一个开始(但我不知道jsofun.css存储在哪里,并且您没有显示任何可用于该文件的代码)。我认为还值得注意的是,您不必index.html在磁盘上创建文件(除非有其他原因需要这样做)。(请参阅 mkopriva 对其他问题和进一步步骤的回答 - 在发布该答案时输入此内容已经进行了一半,并且觉得演练可能仍然有用)。
打开App,查看更多内容
随时随地看视频慕课网APP