英文:
Golang: Shared communication in async http server
问题
绝对的初学者,除了写一个简单的http服务器之外,对golang一无所知。我正在研究Go作为编写异步进程的可能性。如果您可以提供一个快速示例,说明如何实现这一点:
当收到Http请求'a'时,根据该请求中的POST负载(带有某种唯一标识符的POST或URL)启动一个操作。由'a'启动的异步进程将使用原始唯一标识符(请求'b')回复给同一服务器,而请求'a'仍然保持打开状态。我希望根据请求'b'的响应将该响应传递回请求'a'。
英文:
Absolute beginner to golang other than writing a simple http server. I'm researching Go as a possibility for writing an async process. If you could please provide a quick sample of how this might be accomplished:
Http request 'a' comes in, an operation is started based on POST payload in this request (with some sort of unique identifier in post or url). The async process started by 'a' will respond back to same server with original unique identifier (request 'b') while request 'a' is still open. I'd like to communicate that response back to request 'a' based on request 'b' response.
答案1
得分: 7
尽管可以使用通道来实现这一点,但在这种情况下,我更喜欢使用受互斥锁保护的哈希(映射)。
为了给你一个想法并让你开始:
package main
import (
"fmt"
"net/http"
"sync"
)
type state struct {
*sync.Mutex // 继承锁定方法
Vals map[string]string // 将id映射到值
}
var State = &state{&sync.Mutex{}, map[string]string{}}
func get(rw http.ResponseWriter, req *http.Request) {
State.Lock()
defer State.Unlock() // 确保在离开函数后解锁
id := req.URL.Query().Get("id") // 如果你需要其他类型,请查看strconv包
val := State.Vals[id]
delete(State.Vals, id)
rw.Write([]byte("got: " + val))
}
func post(rw http.ResponseWriter, req *http.Request) {
State.Lock()
defer State.Unlock()
id := req.FormValue("id")
State.Vals[id] = req.FormValue("val")
rw.Write([]byte("go to http://localhost:8080/?id=42"))
}
var form = `<html>
<body>
<form action="/" method="POST">
ID: <input name="id" value="42" /><br />
Val: <input name="val" /><br />
<input type="submit" value="submit"/>
</form>
</body>
</html>`
func formHandler(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(form))
}
// 对于真正的路由,请查看gorilla/mux包
func handler(rw http.ResponseWriter, req *http.Request) {
switch req.Method {
case "POST":
post(rw, req)
case "GET":
if req.URL.String() == "/form" {
formHandler(rw, req)
return
}
get(rw, req)
}
}
func main() {
fmt.Println("go to http://localhost:8080/form")
// 这是net/http包的默认web服务器,但你也可以创建自定义服务器
err := http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
if err != nil {
fmt.Println(err)
}
}
英文:
Although it is possible to do this with channels,
I would prefer a hash (map) that is protected by a mutex,
since it is easier in this case.
To give you an idea and get you going:
package main
import (
"fmt"
"net/http"
"sync"
)
type state struct {
*sync.Mutex // inherits locking methods
Vals map[string]string // map ids to values
}
var State = &state{&sync.Mutex{}, map[string]string{}}
func get(rw http.ResponseWriter, req *http.Request) {
State.Lock()
defer State.Unlock() // ensure the lock is removed after leaving the the function
id := req.URL.Query().Get("id") // if you need other types, take a look at strconv package
val := State.Vals[id]
delete(State.Vals, id)
rw.Write([]byte("got: " + val))
}
func post(rw http.ResponseWriter, req *http.Request) {
State.Lock()
defer State.Unlock()
id := req.FormValue("id")
State.Vals[id] = req.FormValue("val")
rw.Write([]byte("go to http://localhost:8080/?id=42"))
}
var form = `<html>
<body>
<form action="/" method="POST">
ID: <input name="id" value="42" /><br />
Val: <input name="val" /><br />
<input type="submit" value="submit"/>
</form>
</body>
</html>`
func formHandler(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(form))
}
// for real routing take a look at gorilla/mux package
func handler(rw http.ResponseWriter, req *http.Request) {
switch req.Method {
case "POST":
post(rw, req)
case "GET":
if req.URL.String() == "/form" {
formHandler(rw, req)
return
}
get(rw, req)
}
}
func main() {
fmt.Println("go to http://localhost:8080/form")
// thats the default webserver of the net/http package, but you may
// create custom servers as well
err := http.ListenAndServe("localhost:8080", http.HandlerFunc(handler))
if err != nil {
fmt.Println(err)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论