为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕码人8056858 2022-11-23 15:57:44

我有一个 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:


查看完整描述

2 回答

?
繁星coding

TA贡献0条经验 获得超4个赞

您的 Go 服务器设置为仅提供/blog/路径服务,它通过执行blogHandler. 在您的 Go 服务器中没有其他任何东西被设置为提供诸如 css、js 或图像文件之类的资产。


对于这样的事情,您通常需要FileServer在单独的路径上注册一个单独的处理程序。例子:


func main() {

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

    // To serve a directory on disk (/path/to/assets/on/my/computer)

    // under an alternate URL path (/assets/), use StripPrefix to

    // modify the request URL's path before the FileServer sees it:

    http.Handle("/assets/", http.StripPrefix("/assets/",

        http.FileServer(http.Dir("/path/to/assets/on/my/computer"))))

    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 {

    Title       string `json:"title"`

    Timestamp   string `json:"timestamp"`

    Main        string `json:"main"`

    ContentInfo string `json:"content_info"`

}


var blogTemplate = template.Must(template.ParseFiles("./blogtemplate.html"))


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

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


    f, err := os.Open(blogstr)

    if err != nil {

        http.Error(w, err.Error(), http.StatusNotFound)

        return

    }

    defer f.Close()


    var post BlogPost

    if err := json.NewDecoder(f).Decode(&post); err != nil {

        http.Error(w, err.Error(), http.StatusInternalServerError)

        return

    }

    if err := blogTemplate.Execute(w, post); err != nil {

        log.Println(err)

    }

}


查看完整回答
反对 回复 2022-11-23
?
呼唤远方

TA贡献1560条经验 获得超11个赞

让我们研究一下当您请求时会发生什么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 对其他问题和进一步步骤的回答 - 在发布该答案时输入此内容已经进行了一半,并且觉得演练可能仍然有用)。


查看完整回答
反对 回复 2022-11-23

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信