在浏览器中显示Go应用程序

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

Displaying Go App In The Browser

问题

我写了一个应用程序,它向API发送请求并获取JSON响应。当我运行应用程序时,它会在终端中显示JSON。

go run main.go

我想让它在浏览器中运行,我找到了以下代码,它允许我将字符串打印到浏览器中。

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "This is a string")
}

func main() {
    http.HandleFunc("/", handler)
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
}

现在,我已经将一个字符串打印到屏幕上,并且我正在使用API获取JSON响应。我想知道如何将JSON响应添加到浏览器而不是字符串中?

是否最好将响应放入一个字符串中,然后将其传递给浏览器?

目前,我是这样将JSON响应打印到终端的:

type Payload struct {
    Page    int
    Results []Data 
}

type Data struct {
    PosterPath       string  `json:"poster_path"`
    Adult            bool    `json:"adult"`
    Overview         string  `json:"overview"`
    ReleaseDate      string  `json:"release_date"`
    GenreIds         []int   `json:"genre_ids"`
    Id               int     `json:"id"`
    OriginalTitle    string  `json:"original_title"`
    OriginalLanguage string  `json:"original_language"`
    Title            string  `json:"title"`
    BackdropPath     string  `json:"backdrop_path"`
    Popularity       float64 `json:"popularity"`
    VoteCount        int     `json:"vote_count"`
    Video            bool    `json:"video"`
    VoteAverage      float64 `json:"vote_average"`
}

func main() {
    for i := 0; i < len(p.Results); i++ {
        fmt.Println(
            ImgUrl+p.Results[i].PosterPath, "\n", p.Results[i].Adult,
            p.Results[i].Overview, "\n", p.Results[i].ReleaseDate,
            p.Results[i].GenreIds, "\n", p.Results[i].Id,
            p.Results[i].OriginalTitle, "\n", p.Results[i].OriginalLanguage,
            p.Results[i].Title, "\n", ImgUrl+p.Results[i].BackdropPath,
            p.Results[i].Popularity, "\n", p.Results[i].VoteCount,
            p.Results[i].Video, "\n", p.Results[i].VoteAverage,
        )
    }
}

在构建Web应用程序时,使用Go语言的最佳方法是什么?我的最终目标是根据用户提供的信息,接受用户输入并重新创建我的API调用。

英文:

I wrote an app that makes a request to an API and gets a JSON response. When I run the app it displays the json in the terminal.

go run main.go

I want to make this run in the browser and I found this, which allowed me to print a string to the browser.

     func handler(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintf(w, &quot;This is a string&quot;)
   }

Then in main

http.HandleFunc(&quot;/&quot;, handler) 
log.Fatal(http.ListenAndServe(&quot;localhost:8000&quot;, nil))

Now that I have a string being printed to the screen and I have a json response coming from the api I am using, how can I add the json response to the browser instead of the string?

Would it be best to put the response into a string then just bring it to the browser?

Currently I am printing the json response to the terminal like this,

type Payload struct {
        Page    int
        Results []Data 
}

type Data struct {
        PosterPath       string  `json:&quot;poster_path&quot;`
        Adult            bool    `json:&quot;adult&quot;`
        Overview         string  `json:&quot;overview&quot;`
        ReleaseDate      string  `json:&quot;release_date&quot;`
        GenreIds         []int   `json:&quot;genre_ids&quot;`
        Id               int     `json:&quot;id&quot;`
        OriginalTitle    string  `json:&quot;original_title&quot;`
        OriginalLanguage string  `json:&quot;original_language&quot;`
        Title            string  `json:&quot;title&quot;`
        BackdropPath     string  `json:&quot;backdrop_path&quot;`
        Popularity       float64 `json:&quot;popularity&quot;`
        VoteCount        int     `json:&quot;vote_count&quot;`
        Video            bool    `json:&quot;video&quot;`
        VoteAverage      float64 `json:&quot;vote_average&quot;`
}

Then inside main() I do this,

    for i := 0; i &lt; len(p.Results); i++ {
    		fmt.Println(
    	  	ImgUrl+p.Results[i].PosterPath, &quot;\n&quot;, p.Results[i].Adult,
    	  	p.Results[i].Overview, &quot;\n&quot;, p.Results[i].ReleaseDate,
    	  	p.Results[i].GenreIds, &quot;\n&quot;, p.Results[i].Id,
    	  	p.Results[i].OriginalTitle, &quot;\n&quot;, p.Results[i].OriginalLanguage,
    	  	p.Results[i].Title, &quot;\n&quot;, ImgUrl+p.Results[i].BackdropPath,
    	  	p.Results[i].Popularity, &quot;\n&quot;, p.Results[i].VoteCount,
    	  	p.Results[i].Video, &quot;\n&quot;, p.Results[i].VoteAverage,
    	  	)

What would be the Go way to do this for building web applications? My end goal here is to take user input and recreate my api call based on the information they provide.

答案1

得分: 1

如果您希望直接将API的响应发送给用户,可以使用io.Copy。在将响应传递给用户之前,您可以检查API请求是否成功,并在失败时发送错误。

一些API会在头部发送信息,就像您使用速率限制一样。因此,在传递之前,您也可以检查头部。

func handler(w http.ResponseWriter, r *http.Request) {
    resp, err := http.Get("http://jsonplaceholder.typicode.com/posts") // 您对API的请求

    w.Header().Set("Content-Type", "application/javascript")

    if err == nil && resp.StatusCode == http.StatusOK {
        io.Copy(w, resp.Body)
    } else {
        json.NewEncoder(w).Encode(err)
    }
}

这样可以避免在您的应用程序上进行任何新的分配。

如果您想像评论中所述那样向客户端发送HTML,请使用html/template包。

当然,您可以手动准备HTML字符串并将其发送给客户端。但是我认为使用模板可以使代码更清晰、更易维护。它还提供了自动转义功能。

例如,以下代码将渲染Payload中每个ResultsOverview部分:

func handler(w http.ResponseWriter, r *http.Request) {
    // 进行API调用并准备`Payload`对象(根据您在问题中的示例)

    for i := 0; i < len(p.Results); i++ {
        fmt.Println(p.Results[i].Overview) // 打印到终端
    }

    // 以下代码将以HTML形式将相同的信息发送到浏览器

    t, err := template.New("foo").Parse(`
        {{define "T"}}
            <html><ul>{{range .Results}}<li>{{.Overview}}</li>{{end}}</ul></html>
        {{end}}`)
    err = t.ExecuteTemplate(w, "T", p) // 这将写入客户端响应
}
英文:

If you are fine with directly sending the response from the API to your users then use io.Copy. You can check if the api request was successful before relaying it to the users and send an error if it did not.

Some APIs send information in headers like how you are doing with the rate limiting. So you can check headers as well before relaying.

func handler(w http.ResponseWriter, r *http.Request) {
	resp, err := http.Get(&quot;http://jsonplaceholder.typicode.com/posts&quot;) // your request to the api

    w.Header().Set(&quot;Content-Type&quot;, &quot;application/javascript&quot;)

	if err == nil &amp;&amp; resp.StatusCode == http.StatusOK {
		io.Copy(w, resp.Body)
	} else {
		json.NewEncoder(w).Encode(err)
	}
}

This avoids making any new allocations on your app.

If you want to send your clients html as stated in comments, use the html/template package.

You can of course prepare a html string manually and send it to the clients. But I think its obvious that using templates makes the code cleaner and maintainable. It also provides autoescaping.

For example following would render the Overview section of each of your Results from the Payload p

func handler(w http.ResponseWriter, r *http.Request) {
    // Make your api call and prepare the `Payload` object (from your example in the question)

    for i := 0; i &lt; len(p.Results); i++ {
       fmt.Println(p.Results[i].Overview) // Prints to your terminal
    }

    // Following sends same information as above to the browser as html

    t, err := template.New(&quot;foo&quot;).Parse(`
      {{define &quot;T&quot;}}
        &lt;html&gt;&lt;ul&gt;{{range .Results}}&lt;li&gt;{{.Overview}}&lt;/li&gt;{{end}}&lt;/ul&gt;&lt;/html&gt;
      {{end}}`)
    err = t.ExecuteTemplate(w, &quot;T&quot;, p) // This writes the client response
}

huangapple
  • 本文由 发表于 2016年3月12日 10:41:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/35953120.html
匿名

发表评论

匿名网友

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

确定