AJAX 拉取是一种解决方案,尽管存在其他可能更适合并节省资源的解决方案*...
例如,拥有一个持久的 Websocket 连接将有助于最大限度地降低建立新连接和重复请求(大多是冗余的)的成本。
因此,您的服务器应具有较低的工作负载,并且您的应用程序将需要较少的带宽(如果这些对您很重要的话)。
即使使用 Websocket 连接只是为了告诉您的客户端何时发送 AJAX 请求有时也可以节省资源。
这是一个快速的 Websocket Push 演示
您可以使用许多不同的 Websocket 解决方案。我使用the Plezi framework 编写了一个快速演示,因为它非常容易实现,但还有其他方法可以解决这个问题。
Plezi 框架是一个 Ruby 框架,运行它自己的 HTTP 和 Websocket 服务器,独立于 Rack。
示例代码包括一个模型控制器(DemoController)、一个根索引页面控制器(DemoIndex)和一个Websocket连接控制器(MyWSController)。
示例代码似乎更长,因为它都在一个脚本中 - 甚至用作客户端的 HTML 页面......但它真的很容易阅读。
搜索要求从客户端发送到网络服务器(搜索要求模型的对象 ID 介于 0 和 50 之间)。
每次创建(或更新)对象时,都会向所有连接的客户端发送警报,首先运行每个客户端的搜索,然后发送任何更新。
服务器休息的其余时间(除了每 45 秒左右 ping 一次,以保持 websocket 连接处于活动状态)。
要查看实际演示,只需将以下代码复制并粘贴到您的 IRB 终端**,然后访问演示页面:
require 'plezi'
class MyWSController
def on_open
# save the user data / register them / whatever
@searches = []
end
def on_message data
# get data from the user
data = JSON.parse data
# sanitize data, create search parameters...
raise "injection attempt: #{data}}" unless data['id'].match(/^\([\d]+\.\.[\d]+\)\z/)
# save the search
@searches << data
end
def _alert options
# should check @searches here
@searches.each do |search|
if eval(search['id']).include? options[:info][:id]
# update
response << {event: 'alert'}.merge(options).to_json
else
response << "A message wouldn't be sent for id = #{options[:info][:id]}.\nSaved resources."
end
end
end
end
class DemoController
def index
"use POST to post data here"
end
# called when a new object is created using POST
def save
# ... save data posted in params ... then:
_send_alert
end
# called when an existing object is posted using POST or UPDATE
def update
# ... update data posted in params ... then:
_send_alert
end
def demo_update
_send_alert message: 'info has been entered', info: params.update(id: rand(100), test: 'true')
" This is a demo for what happens when a model is updated.\n
Please Have a look at the Websocket log for the message sent."
end
# sends an alert to
def _send_alert alert_data
MyWSController.broadcast :_alert, alert_data
end
end
class DemoIndex
def index search = '(0..50)'
response['content-type'] = 'text/html'
<<-FINISH
<html>
<head>
<style>
html, body {height: 100%; width:100%;}
#output {margin:0 5%; padding: 1em 2em; background-color:#ddd;}
#output li {margin: 0.5em 0; color: #33f;}
</style>
</head><body>
<h1> Welcome to your Websocket Push Client </h1>
<p>Please open the following link in a <b>new</b> tab or browser, to simulate a model being updated: <a href='#{DemoController.url_for id: :demo_update, name: 'John Smith', email: 'john@gmail.com'}', target='_blank'>update simulation</a></p>
<p>Remember to keep this window open to view how a simulated update effects this page.</p>
<p>You can also open a new client (preferably in a new tab, window or browser) that will search only for id's between 50 and 100: <a href='#{DemoIndex.url_for :alt_search}'>alternative search</a></p>
<p>Websocket messages recieved from the server should appeare below:</p>
<ul id='output'>
</ul>
<script>
var search_1 = JSON.stringify({id: '#{search}'})
output = document.getElementById("output");
websocket = new WebSocket("#{request.base_url 'ws'}/ws");
websocket.onmessage = function(e) { output.innerHTML += "<li>" + e.data + "</li>" }
websocket.onopen = function(e) { websocket.send(search_1) }
</script>
</body></html>
FINISH
end
def alt_search
index '(50..100)'
end
end
listen
route '/model', DemoController
route '/ws', MyWSController
route '/', DemoIndex
exit
要查看此演示,请访问 localhost:3000 并按照屏幕上的说明进行操作。
该演示将指导您打开多个浏览器窗口,模拟不同的人访问您的服务器并执行不同的操作。
如您所见,客户端 javascript 和服务器端处理都不是很难编写,而 Websockets 提供了非常高的灵活性并允许更好的资源管理(例如,搜索参数需要不会一遍又一遍地发送到服务器)。
* 适合您应用的最佳解决方案取决于您的具体设计。我只是提供另一种观点。
** ruby 的终端使用bash 中的irb 运行,请确保首先使用gem install plezi 安装plezi 网络