我想实现一个仪表板(网页),它允许授权连接的客户机与服务器(运行Tornado,Python的服务器)交互。当前授权的客户机存储在服务器上的“客户机阵列”中。仪表板正在长时间轮询更新,因此一旦发生更改,它就会显示阵列中的更改。
由于客户机可以通过仪表板中的按钮进行授权,因此必须同时向服务器发送授权请求以进行长轮询。你知道吗
顺便说一句:我知道,对于这个特定的用例,长轮询是没有必要的。但是项目后面还有其他需要长时间轮询的情况,所以我也尝试将其用于这个情况。你知道吗
加载仪表板(以及当前连接的客户端)后,仪表板将开始长时间轮询更新。服务器知道此连接并等待更改发生。
当通过按键对客户机进行授权时,服务器接收到授权请求并分别更改客户机阵列。这些更改导致服务器将更新的HTML发送到仪表板。之后,它将发送另一个对授权请求的响应。你知道吗
但是仪表板没有接收到服务器发送的更新的HTML。好像它从未被发送过,或者仪表板不知何故不再等待它。
不过,通过按钮触发的授权请求的响应将被接收。你知道吗
有人能解释我做错了什么吗?你知道吗
注意下面的编辑
仪表板的代码(JavaScript):
window.onload = function() {
requestClientUpdates();
};
async function requestClientUpdates() {
let response = await fetch(window.location.pathname, {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: "req-type=update" // request for getting updates
});
if (response.status === 502) {
console.log("502: " + response.statusText);
} else if (response.status !== 200) {
console.log(response.statusText);
} else {
updateDashboardHTML(response.text()); // dummy function
// this doesn't ever get called
}
requestClientUpdates(); // immediately poll for updates again
}
// triggered on button-press
function authorizeClient() {
var data = "req-type=authorize-client"; // along with some more data
let response = fetch(window.location.pathname, {
method: 'POST',
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: data
});
if (response.status === 502) {
console.log("502: " + response.statusText);
} else if (response.status !== 200) {
console.log(response.statusText);
} else {
console.log("authorized");
// gets called
}
}
用于长时间轮询和命令请求的服务器处理程序(带有Tornado框架的Python):
class ClientManager(object):
def __init__(self):
self.condition = tornado.locks.Condition()
self.authorized_clients = []
def authorize_client(self, id):
"""Adds client with given ID to connected clients"""
client = get_client(id) # returns client object with more data
self.authorized_clients.append(client)
self.announce_update()
def announce_update(self):
self.condition.notify()
client_manager = ClientManager()
class MainHandler(BaseHandler):
def send_current_client_overview(self):
data = generatingHTMLforDashboard() # dummy for the actual code
self.write(data) # is reached properly (as tests have shown)
async def post(self):
req_type = self.get_arguments("req-type")
if "authorize-client" in req_type:
client_manager.authorize_client(self.get_argument("id"))
elif "update" in req_type:
await client_manager.condition.wait()
self.send_current_client_overview()
def main():
app.listen(port) # server application was prepared before
tornado.ioloop.IOLoop.current().start()
[见下文评论]收到回复,但仅在特定情况下。在服务器重新启动并且仪表板重新进入之后(不仅仅是刷新)。以前不能运行JavaScript)。一旦仪表板被刷新,它就不再工作,服务器必须重新启动等等
进行了多项更改:
等待回复.text(),即使您已经在等待响应。否则,承诺“回应”可能还没有实现。你知道吗
async function requestClientUpdates() {
let response = await fetch(window.location.pathname, {
// pack request
});
// catch errors
else {
var answer = await response.text(); // make sure it is fulfilled before usage
// continue working with answer
}
requestClientUpdates(); // immediately poll for updates again
}
#2(这导致了问题):一旦连接关闭,就取消未来。因此,覆盖处理程序的on\u connection\u close():
class MainHandler(BaseHandler):
def initialize(self):
self.wait_future = None
async def post(self):
if "update" in req_type:
# save Future returned here so it can be canceled on on_connection_close()
self.wait_future = client_manager.condition.wait()
try:
await self.wait_future
# catch exception in case future was cancelled due to a closed connection
except asyncio.CancelledError:
return
self.send_current_client_overview()
def on_connection_close(self):
if self.wait_future is not None:
self.wait_future.cancel()
在刷新页面后,这些更改仍然会使代码在fortox的控制台中打印一个TypeError: NetworkError when attempting to fetch resource.
,但除此之外,仪表板的行为与预期一致。你知道吗
目前没有回答
相关问题 更多 >
编程相关推荐