Asynchronous request for multiple response golang

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

Asynchronous request for multiple response golang

问题

我需要向一个服务器发出请求,该服务器在不同的时间返回不同的响应。我的意思是,服务器会生成不同的响应,并且这些响应的执行时间也不同,所以服务器会在可用时立即返回这些响应。

我想要将这些响应打印在屏幕上(目前,我只满足于这一点),即服务器返回响应后立即打印。

到目前为止,我只能在服务器返回所有响应时才打印这些响应。所以如果第一个响应需要1秒,最后一个响应需要10秒,我的代码需要等待10秒才能打印所有消息。

编辑:添加了我的代码:

// 从yml文件中获取配置
RestConfig := Config["rest"].(map[string]interface{})
ServerConfig := Config["server"].(map[string]interface{})
RequestUrl := ServerConfig["url"]

RequestReader := bytes.NewReader(body)
Request, _ := http.NewRequest("POST", RequestUrl.(string), RequestReader)

// 将所需的头部信息添加到请求中
client.AppendHeaders(Request, RestConfig["headers"])

// client.HttpClient 的类型是 *http.Client
Response, _ := client.HttpClient.Do(Request)

// 打印在屏幕上
defer Response.Body.Close()

fmt.Println("-> Receiving response:\n---\n")
fmt.Println(Response, "\n---\n-> Response body:\n---\n")
body_resp, _ := ioutil.ReadAll(Response.Body)
fmt.Println(string(body_resp))
fmt.Println("\n--\n")

有什么办法可以实现吗?

非常感谢。

英文:

I need to make a request to a server that return different responses at different times. I mean, the server generate different responses and these responses take different execution time, so server return the responses as soon as they are available.

And I want print in the screen (by the moment, I'd settle with that) these responses as soon as the server returns me.

All what I could do until now is print the responses but only when the server returns all the responses. So if the first response take 1sec, and the last response take 10sec, my code needs to wait 10sec to print all the messages.

EDIT: to add code I have:

//Config is gotten from yml file
RestConfig 		 = Config["rest"].(map[string]interface{})
ServerConfig 	 = Config["server"].(map[string]interface{})
RequestUrl 		:= ServerConfig["url"]

RequestReader   := bytes.NewReader(body)
Request, _ 		:= http.NewRequest("POST", RequestUrl.(string), RequestReader)

//AppendHeaders append the needing headers to the request 
client.AppendHeaders(Request, RestConfig["headers"])

//the type of client.HttpClient is *http.Client
Response, _ 	:= client.HttpClient.Do(Request)

//And to print in the screen
defer Response.Body.Close()

fmt.Println( "-> Receiving response:\n---\n" )
fmt.Println( Response , "\n---\n-> Response body:\n---\n")
body_resp, _ := ioutil.ReadAll(Response.Body)
fmt.Println( string(body_resp) )
fmt.Println( "\n--\n")

Any way to do it??

Thank you very much.

答案1

得分: 6

最终我的代码是这样的:

package main

import (
	"fmt"
	"log"
	"bytes"
	"strings"
	"bufio"
	"net/http"
)

func main() {
	var body = "The body"
	RequestReader := bytes.NewReader([]byte(body))
	req, err := http.NewRequest("POST", "the_url", RequestReader)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Add("Accept", "application/xml")
	req.Header.Add("Content-Type", "application/xml")
	req.Header.Add("AG-Authorization", "key")
	req.Header.Add("AG-Forwarded-Hosts", "*")

	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	reader := bufio.NewReader(resp.Body)
	message := ""
	for {
		line, err := reader.ReadBytes('\n')
		if err != nil {
			log.Fatal(err)
		}
		message = message + string(line)
		if strings.Contains(message, "<!-- End mark for each message -->"){
			fmt.Println(message)
			message = ""
		}
	}
}

谢谢大家。

英文:

Finally my code , is like this:

package main

import (
    &quot;fmt&quot;
    &quot;log&quot;
    &quot;bytes&quot;
    &quot;strings&quot;
    &quot;bufio&quot;
    &quot;net/http&quot;
)

func main() {
  var body = &quot;The body&quot;
  RequestReader := bytes.NewReader([]byte(body))
  req, err := http.NewRequest(&quot;POST&quot;, &quot;the_url&quot;, RequestReader)
  if err != nil {
    log.Fatal(err)
  }
  req.Header.Add(&quot;Accept&quot;, &quot;application/xml&quot;)
  req.Header.Add(&quot;Content-Type&quot;, &quot;application/xml&quot;)
  req.Header.Add(&quot;AG-Authorization&quot;, &quot;key&quot;)
  req.Header.Add(&quot;AG-Forwarded-Hosts&quot;, &quot;*&quot;)

  resp, err := (&amp;http.Client{}).Do(req)
  if err != nil {
    log.Fatal(err)
  }
  reader := bufio.NewReader(resp.Body)
  message := &quot;&quot;
  for {
	line, err := reader.ReadBytes(&#39;\n&#39;)
    if err != nil {
      log.Fatal(err)
 }
	message = message + string(line)
	if strings.Contains(message, &quot;&lt;!-- End mark for each message --&gt;&quot;){
		fmt.Println(message)
		message = &quot;&quot;
	}
  }
}

Thank everyone.

答案2

得分: 1

context包是你要找的内容。

context包负责处理进程和服务器请求的信号取消和操作截止时间。它有两个公共方法:WithCancelWithTimeout。与传入请求相关联的Context通常在请求处理程序返回时被取消。

对于你的特定情况,你可以使用WithTimeout方法为后端服务器的请求设置截止时间。

以下是从https://blog.golang.org/context/server/server.go中摘录的代码片段:

timeout, err := time.ParseDuration(req.FormValue("timeout")) // 在你的post中设置时间限制
if err == nil {
    // 请求有一个截止时间,因此创建一个在截止时间到期时自动取消的上下文。
    ctx, cancel = context.WithTimeout(context.Background(), timeout)
} else {
    ctx, cancel = context.WithCancel(context.Background())
}
defer cancel() // 在handleSearch返回时取消ctx。

如果想进一步了解,请阅读这篇文章:
https://blog.golang.org/context

英文:

The context package is what you are looking for.

The context package is responsible for signal cancelation and operation deadlines for processes and server requests. This has two public methods: WithCancel and WithTimeout. The Context associated with an incoming request is typically canceled when the request handler returns.

For your specific case you can use the WithTimeout method for setting a deadline on requests to backend servers.

// WithTimeout returns a copy of parent whose Done channel is closed as soon as
// parent.Done is closed, cancel is called, or timeout elapses. The new
// Context&#39;s Deadline is the sooner of now+timeout and the parent&#39;s deadline, if
// any. If the timer is still running, the cancel function releases its
// resources.
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

And here is a snippet taken from https://blog.golang.org/context/server/server.go

timeout, err := time.ParseDuration(req.FormValue(&quot;timeout&quot;)) // set a time limit in your post
if err == nil {
	// The request has a timeout, so create a context that is
	// canceled automatically when the timeout expires.
	ctx, cancel = context.WithTimeout(context.Background(), timeout)
} else {
	ctx, cancel = context.WithCancel(context.Background())
}
defer cancel() // Cancel ctx as soon as handleSearch returns.

For further reading take a look at this article:
https://blog.golang.org/context

huangapple
  • 本文由 发表于 2016年11月3日 16:45:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/40397076.html
匿名

发表评论

匿名网友

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

确定