2016-09-26 33 views
3

當試圖將值傳入.html代碼時,我使用的是html/template包。如何在Go中使用HTML/TEMPLATE包時設置不同的內容類型

但是,我似乎無法設置我的.html文件中引用的.css內容類型。它被作爲純文本提供給瀏覽器,因此格式被忽略。

在靜態的.html文件中,我可以使用內置的http.Fileserver,它負責處理內容類型,但是模板不起作用。我無法傳入變量。它只是顯示爲{{.}}

有沒有辦法給content-type方便的內置文件服務器http.Fileserver用的http.HandleFunc模板的能力結合起來?

這是我的代碼,因爲它沒有使用http.Fileserver。請注意,我Go文件在啓動目錄和index.html.css文件是一個子目錄/hello/

package main 

import (
     "html/template" 
     "io/ioutil" 
     "log" 
     "net/http" 
) 

var Message string = "test page" 

func servePipe(w http.ResponseWriter, req *http.Request) { 

     dat, err := ioutil.ReadFile("hello/index.html") 
     if err != nil { 
       log.Fatal("couldn't read file:", err) 
     } 

     templ, err := template.New("Test").Parse(string(dat)) 

     if err != nil { 
       log.Fatal("couldn't parse page:", err) 
     } 

     templ.Execute(w, Message) 

} 

func main() { 

     http.HandleFunc("/hello/", servePipe) 
     http.ListenAndServe(":8080", nil) 
} 

這是我.html文件。 html頁面沒有任何問題。這是獨立的.css文件沒有被提供(鏈接在.html文件中),因此格式不會發生。

<!DOCTYPE html> 
<html> 
<head> 
<title>Test Page</title> 

     <link rel="stylesheet" type="text/css" href="style.css"/> 
</head> 

<body> 

     <p>{{.}}</p> 

</body> 
</html> 

回答

3

Template.Execute()將通過調用傳遞io.Writer而你的情況是http.ResponseWriterWrite()方法「提供」的內容。

如果在第一次調用ResponseWriter.Write()(在本例中不是這樣)之前沒有設置內容類型,那麼net/http包將嘗試檢測內容類型(基於寫入的前512個字節) ,並會自動爲您設置(如果ResponseWriter.WriteHeader()尚未被調用,則爲WriteHeader(http.StatusOK))。

這是記錄在http.ResponseWriter.Write()

// Write writes the data to the connection as part of an HTTP reply. 
// 
// If WriteHeader has not yet been called, Write calls 
// WriteHeader(http.StatusOK) before writing the data. If the Header 
// does not contain a Content-Type line, Write adds a Content-Type set 
// to the result of passing the initial 512 bytes of written data to 
// DetectContentType. 
// 
// ... 
Write([]byte) (int, error) 

因此,如果您index.html應該是這樣的:

<html> 
    <body> 
    This is the body! 
    </body> 
</html> 

那麼這將被正確地識別爲一個HTML文檔,從而text/html內容類型會自動設置。如果這不會發生在您身上,那意味着您的index.html未被識別爲HTML文檔。所以,只要確保你使你的模板文件有效的HTML/CSS /等文件和內容類型將被自動和正確地推斷。

還要注意的是,如果它不會在一些「極端」的情況下工作,你總是可以通過事先手動設置它來調用Template.Execute()這樣的「越權」吧:

w.Header().Set("Content-Type", "text/html") 
templ.Execute(w, Message) 

邊注:不要T上讀和解析您的處理程序中的模板,詳見相關的問題:It takes too much time when using "template" package to generate a dynamic web page to client in golang


如果您引用其他模板提供的模板,他們不會被神奇地加載和執行。在這種情況下,您應該有一個包含所有模板的「預加載」模板。 template.ParseFiles()template.ParseGlob()是很好的「工具」一次加載多個模板文件。

因此,如果您的index.html參考style.css,那麼你也必須注意服務style.css太。如果它不是模板(但是例如靜態文件),則可以使用這裏給出的多個選項來提供它:Include js file in Go template

如果它也是一個模板,那麼你也必須加載它並通過調用Template.ExecuteTemplate()來提供它。

一個示例解決方案是使用template.ParseFiles()加載這兩個文件,並使用該路徑「指定」您想要服務的模板(從客戶端/瀏覽器端)。

E.g.請求路徑/hello/index.html可以爲"index.html"模板服務,請求路徑/hello/style.css這將由瀏覽器在接收和處理index.html後自動完成)可以爲"style.css"模板服務。它可能看起來像這樣(爲簡潔起見省略了錯誤檢查):

parts := strings.Split(req.URL.Path, "/") // Parts of the path 
templName := parts[len(parts)-1]   // The last part 
templ.ExecuteTemplate(w, templName, someDataForTemplate) 
+1

謝謝!這非常翔實!我現在手動單獨地爲我的.css樣式表提供服務(現在它可以工作!),但是我正在閱讀規範中的ParseFiles和ParseGlob,以便按照您的建議進行優雅地操作。 – nosequeldeebee

+1

感謝您也指出需要避免解析我的處理程序。我會審查。 – nosequeldeebee

1

模板即生成HTML這是HTTP響應的主體完全從其中經由HTTP報頭中發送的內容類型decoupeled。只需設置的Content-Type到任何合適通過tmpl.Execute(w, ...)生成體:

w.Header().Set("Content-Type", "text/css") 
相關問題