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条)

报告相同问题?

悬赏问题

  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计