如何在golang http服务器中向客户端写入数据然后退出进程?

问题描述 投票:0回答:1

我正在写一个具有自我更新功能的http服务器,步骤是:

  1. 客户端将新的可执行文件作为 http 正文发送到服务器
  2. 服务器用字节替换自身
  3. 服务器向客户端回显字符串“ok”
  4. 服务器退出进程
  5. 服务器将由systemd服务重新启动

问题是当服务器调用

os.Exit()
时,客户端将收到
EOF
而不是“ok”,我的代码如下:

服务器:

package main

import (
    "io"
    "net/http"
    "os"
)

func replace_self_executable(executable_bytes []byte) {
    // ...
}

func handle_self_update(w http.ResponseWriter, r *http.Request) {
    executable_bytes, _ := io.ReadAll(r.Body)

    replace_self_executable(executable_bytes)

    w.Write([]byte(`ok`))

    os.Exit(0)

    // other stuff
}

func main() {
    http.HandleFunc("/self_update", handle_self_update)

    http.ListenAndServe(":123", nil)
}

客户:

package main

import (
    "bytes"
    "fmt"
    "io"
    "net/http"
)

func main() {

    new_server_binary := []byte{ /*...*/ }

    resp, err := http.Post(`http://localhost:123/self_update`, ``, bytes.NewReader(new_server_binary))
    if err != nil {
        panic(err)
    }

    result, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(err)
    }
    fmt.Println(`result`, string(result))
}

我也尝试先刷新并关闭客户端,似乎没有什么区别:

    if f, ok := w.(http.Flusher); ok {
        f.Flush()
    }
    r.Body.Close()

如何向客户发送“ok”?

go httpserver
1个回答
0
投票

向处理程序外部的例程发出信号(例如通过通道),以便您可以从请求处理程序返回并优雅地关闭服务器

func handle_self_update(w http.ResponseWriter, r *http.Request) {
    executable_bytes, _ := io.ReadAll(r.Body)

    replace_self_executable(executable_bytes)

    quitChan <- true

    w.Write([]byte(`ok`))
}

func main() {
    go func() {
        _ := <- quitChan
        // Graceful shutdown
    }

    // Start server
}

一个不相关的说明 - 在实施时要非常非常非常小心。允许客户端向您发布将在服务器上运行的新二进制文件是一个巨大的安全漏洞,并且应该具有身份验证、签名验证、校验和验证等层。或者更好的是,让客户端发出更新信号可用,并且让服务器联系已知良好的源来获取更新的二进制文件(并且仍然确认签名和校验和)。

© www.soinside.com 2019 - 2024. All rights reserved.