golang传递http.ResponseWriter

huangapple go评论89阅读模式
英文:

golang passing http.ResponseWriter

问题

我正在尝试弄清楚在编写Web应用程序时是否有可能不必在每个地方都传递http.ResponseWriter。我正在设置一个简单的MVC Web框架,发现自己不得不在各种函数中传递http.ResponseWriter,而它只在最后一个函数中使用。

Routes包

// 包含HTTP请求和变量的结构体
type UrlInfo struct {
    Res  http.ResponseWriter
    Req  *http.Request
    Vars map[string]string
}

func HandleFunc(handlepath string, runfunc func(*UrlInfo)) {
    // 设置处理程序并设置结构体
    http.HandleFunc(getHandlePath(handlepath), func(w http.ResponseWriter, r *http.Request) {
        url := new(UrlInfo)
        url.Res = w
        url.Req = r
        url.Vars = parsePathVars(r.URL.Path, handlepath)

        runfunc(url)
    })
}

// 解析文件并发送到ResponseWriter
func View(w http.ResponseWriter, path string, data interface{}) {
    // 从views文件夹中获取文件
    temp, err := template.ParseFiles(path + ".html")
    if err != nil {
        // 找不到HTML文件,发送错误
        http.Error(w, err.Error(), http.StatusInternalServerError)
    } else {
        temp.ExecuteTemplate(w, temp.Name(), data)
    }
}

Controller包

import (
    "routes"
)

func init() {
    // 构建HandleFunc
    routes.HandleFunc("/home/", home)
}

func home(urlinfo *routes.UrlInfo) {
    info := make(map[string]string)
    info["Title"] = urlinfo.Vars["title"]
    info["Body"] = "Body Info"

    gi.View(urlinfo.Res, "pages/about", info)
}

我希望在home函数中不必传递任何东西,只需将其再次传递给View函数进行输出。希望能够在一个地方设置它并在需要时从中获取。这对于以相同方式与routes包通信的多个包也很有用。

欢迎任何想法、技巧或窍门。谢谢。

英文:

I am trying to figure out if its possible to not have to pass along the http.ResponseWriter everywhere i go when programming a web application. I am setting up a simple mvc web framework and i find myself having to pass the http.ResponseWriter through various functions when its only used in lets say the last function.

Routes package
<!-- language: lang-go -->

// Struct containing http requests and variables
type UrlInfo struct {
	Res http.ResponseWriter
	Req *http.Request
	Vars map[string]string
}

func HandleFunc(handlepath string, runfunc func(*UrlInfo)) {
	// Set handler and setup struct
	http.HandleFunc(getHandlePath(handlepath), func(w http.ResponseWriter, r *http.Request) {
		url := new(UrlInfo)
	 	url.Res = w
	 	url.Req = r
	 	url.Vars = parsePathVars(r.URL.Path, handlepath)

		runfunc(url)
	})
}

// Parse file and send to responsewriter
func View(w http.ResponseWriter, path string, data interface{}) {
	// Go grab file from views folder
	temp, err := template.ParseFiles(path+&quot;.html&quot;)
	if err != nil {
		// Couldnt find html file send error
		http.Error(w, err.Error(), http.StatusInternalServerError)
	} else {
		temp.ExecuteTemplate(w, temp.Name(), data)
	}
}

Controller package
<!-- language: lang-go -->

import (
	&quot;routes&quot;
)

func init() {
	// Build handlefunc
	routes.HandleFunc(&quot;/home/&quot;, home)
}

func home(urlinfo *routes.UrlInfo) {
	info := make(map[string]string)
	info[&quot;Title&quot;] = urlinfo.Vars[&quot;title&quot;]
	info[&quot;Body&quot;] = &quot;Body Info&quot;

	gi.View(urlinfo.Res, &quot;pages/about&quot;, info)
}

I would like to not have to pass anything in the home function just so i can pass it again to the view function to spit out. Would be nice to be able to set it in one place and pull from it whenever needed. This would also nice in regard to multiple packages that communicate to the routes package in the same regard.

Any and all thoughts, tips or tricks are welcome. Thanks.

答案1

得分: 5

有几种方法可以做到这一点。关键是要弄清楚你实际上需要从传递的 ResponseWriter 中得到什么。听起来你只需要运用一点函数组合的技巧。

改变你的设计,使得 View 函数返回一个 io.Reader 和一个错误,然后将其传递给 ResponseWriter。这是一个完全未经测试的示例:

func View(path string, data interface{}) (io.Reader, error) {
    // 从 views 文件夹中获取文件
    temp, err := template.ParseFiles(path+".html")
    if err != nil {
        // 找不到 html 文件,返回错误
       return nil, err
    } else {
        buf := bytes.Buffer()
        temp.ExecuteTemplate(buf, temp.Name(), data)
        return buf
    }
}

func HandleFunc(handlepath string, runfunc func(*UrlInfo) (io.Reader, error)) {
    // 设置处理程序并设置结构体
    http.HandleFunc(getHandlePath(handlepath),
                    func(w http.ResponseWriter, r *http.Request) {
        url := new(UrlInfo)
        url.Res = w
        url.Req = r
        url.Vars = parsePathVars(r.URL.Path, handlepath)

        rdr, err := runfunc(url)
        io.Copy(w, rdr);
    })
}

使用这种方法,唯一需要关心 http ResponseWriter 的是 HandleFunc 函数。

英文:

There are a number of ways you can do this. The trick is to figure out what is you actually need from the ResponseWriter you are passing through. It sounds like you just need to exercise a little function composition.

Change your design so that the View returns an io.Reader, and an error that you can then pipe into the ResponseWriter. Here's a completely untested example:

func View(path string, data interface{}) (io.Reader, error) {
    // Go grab file from views folder
    temp, err := template.ParseFiles(path+&quot;.html&quot;)
    if err != nil {
        // Couldnt find html file send error
       return nil, err
    } else {
        buf := bytes.Buffer()
        temp.ExecuteTemplate(buf, temp.Name(), data)
        return buf
    }
}

func HandleFunc(handlepath string, runfunc func(*UrlInfo) (io.Reader, error)) {
    // Set handler and setup struct
    http.HandleFunc(getHandlePath(handlepath),
                    func(w http.ResponseWriter, r *http.Request) {
        url := new(UrlInfo)
        url.Res = w
        url.Req = r
        url.Vars = parsePathVars(r.URL.Path, handlepath)

        rdr, err := runfunc(url)
        io.Copy(w, rdr);
    })
}

With this the only thing that has to worry about the http ResponseWriter is your HandleFunc function.

huangapple
  • 本文由 发表于 2012年9月21日 03:33:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/12519660.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定