dongxun7962 2018-07-15 15:32
浏览 47
已采纳

如何使用REST API将消息正确发布到简单的Go Chatserver

I am currently building a simple chat server that supports posting messages through a REST API.

 example:
 ========

 ```
 curl -X POST -H "Content-Type: application/json" --data '{"user":"alex", "text":"this is a message"}' http://localhost:8081/message

 {
   "ok": true
 }

Right now, I'm just currently storing the messages in an array of messages. I'm pretty sure this is an inefficient way. So is there a simple, better way to get and store the messages using goroutines and channels that will make it thread-safe.

Here is what I currently have:

type Message struct {
    Text string
    User string
    Timestamp time.Time
}

var Messages = []Message{}


func messagePost(c http.ResponseWriter, req *http.Request){
    decoder := json.NewDecoder(req.Body)
    var m Message
    err := decoder.Decode(&m)
    if err != nil {
        panic(err)
    }
    if m.Timestamp == (time.Time{}) {
        m.Timestamp = time.Now()
    }
    addUser(m.User)
    Messages = append(Messages, m)
}

Thanks!

  • 写回答

2条回答 默认 最新

  • dra87370 2018-07-15 22:42
    关注

    It could be made thread safe using mutex, as @ThunderCat suggested but I think this does not add concurrency. If two or more requests are made simultaneously, one will have to wait for the other to complete first, slowing the server down.

    Adding Concurrency: You make it faster and handle more concurrent request by using a queue (which is a Go channel) and a worker that listens on that channel - it'll be a simple implementation. Every time a message comes in through a Post request, you add to the queue (this is instantaneous and the HTTP response can be sent immediately). In another goroutine, you detect that a message has been added to the queue, you take it out append it to your Messages slice. While you're appending to Messages, the HTTP requests don't have to wait.

    Note: You can make it even better by having multiple goroutines listen on the queue, but we can leave that for later.

    This is how the code will somewhat look like:

    type Message struct {
        Text string
        User string
        Timestamp time.Time
    }
    
    var Messages = []Message{}
    
    // messageQueue is the queue that holds new messages until they are processed
    var messageQueue chan Message
    
    func init() { // need the init function to initialize the channel, and the listeners
        // initialize the queue, choosing the buffer size as 8 (number of messages the channel can hold at once)
        messageQueue = make(chan Message, 8) 
    
        // start a goroutine that listens on the queue/channel for new messages
        go listenForMessages()
    }
    
    func listenForMessages() {
        // whenever we detect a message in the queue, append it to Messages
        for m := range messageQueue {
            Messages = append(Messages, m)
        }
    }
    
    func messagePost(c http.ResponseWriter, req *http.Request){
        decoder := json.NewDecoder(req.Body)
        var m Message
        err := decoder.Decode(&m)
        if err != nil {
            panic(err)
        }
        if m.Timestamp == (time.Time{}) {
            m.Timestamp = time.Now()
        }
        addUser(m.User)
    
        // add the message to the channel, it'll only wait if the channel is full
        messageQueue <- m 
    }
    

    Storing Messages: As other users have suggested, storing messages in memory may not be the right choice since the messages won't persist if the application is restarted. If you're working on a small, proof-of-concept type project and don't want to figure out the DB, you could save the Messages variable as a flat file on the server and then read from it every time the application starts (*Note: this should not be done on a production system, of course, for that you should set up a Database). But yeah, database should be the way to go.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源