在 websockets 之前,我们有轮询。这实际上意味着让客户端定期(每隔几秒,或任何对您的应用程序有意义的时间段)向服务器发出请求以了解作业的状态。
许多人使用的优化是“长”轮询。这涉及让服务器接受请求,并在服务器内部检查更改,并在没有更改时休眠,直到达到特定超时或发生所需事件,然后将其返回给客户端。
如果达到超时,连接将关闭,客户端需要发出另一个请求。服务器代码如下所示,假设函数根据其名称和签名执行合理的操作:
import (
"net/http"
"time"
)
func PollingHandler(w http.ResponseWriter, r *http.Request) {
jobID := getJobID(r)
for finish := 60; finish > 0; finish-- { // iterate for ~1 minute
status, err := checkStatus(jobID)
if err != nil {
writeError(w, err)
return
}
if status != nil {
writeStatus(w, status)
return
}
time.Sleep(time.Second) // sleep 1 second
}
writeNil(w) // specific response telling client to request again.
}
处理超时的更好方法是使用上下文包并创建一个带有超时的上下文。这看起来像:
import (
"net/http"
"time"
"golang.org/x/net/context"
)
func PollingHandler(w http.ResponseWriter, r *http.Request) {
jobID := getJobID(r)
ctx := context.WithTimeout(context.Background(), time.Second * 60)
for {
select{
case <-ctx.Done():
writeNil(w)
default:
status, err := checkStatus(jobID)
if err != nil {
writeError(w, err)
return
}
if status != nil {
writeStatus(w, status)
return
}
time.Sleep(time.Second) // sleep 1 second
}
}
}
第二个版本将在更可靠的时间内返回,尤其是在checkStatus
调用速度可能较慢的情况下。