【问题标题】:How can I push data to a browser where the data is based on a SQL statement? [closed]如何将数据推送到数据基于 SQL 语句的浏览器? [关闭]
【发布时间】:2015-06-18 14:28:00
【问题描述】:

我知道有关于这个主题的线索,但似乎确实回答了我正在寻找的东西。我以前从未做过任何推送技术,所以这里的一些指导表示赞赏。我了解当某些事情发生变化时会触发推送到正在侦听的任何浏览器,但我认为这不太适合我正在尝试做的场景。

我们正在重建我们的用户 Web 应用程序,他们可以在其中跟踪货物。我们将允许用户在那里建立自己的搜索,以匹配他们的工作方式。例如,有些人会寻找计划在今天交付的任何货物,而另一些人会寻找今天要取货的货物,还有一些人会寻找需要安排取货的货物。因此,当他们打开应用程序时,我可以为他们今天需要完成的每项工作任务计数。所以现在我想要的是计数将根据重新运行的 SQL 而改变。但我不希望用户必须刷新页面才能看到新计数。

如何运行此 SQL 并将当前计数推送到使用此 SQL 的任何浏览器。自动重新运行此 SQL 的机制是什么?请记住,我将有 50 个或更多这些独特的 SQL 需要执行并推送计数。

感谢您的指导!

【问题讨论】:

    标签: websocket push-notification long-polling polling


    【解决方案1】:

    我认为这完全符合 AJAX 的角色。 AJAX 将允许您向服务器发出 GET 和 POST 请求,服务器将处理查询并将结果返回给 JS 函数。冒着 jQuery 传播的风险,API 使这种事情变得非常简单和标准,您几乎可以拥有任何想要激活它的事件。

    这有几个问题,即客户端输入和 SQL 注入。如果您通过 POST 请求发送任何输入,则必须非常小心地清理所有内容。使用准备好的语句,不要执行查询字符串连接+执行,并且通常假设用户会尝试发送您不希望他们发送的文本。为哪些输入将被成功确认提供一些服务器端边界(例如,如果选项是“左”或“右”,并且它们给出“底部”,则默认或放弃)。

    1. 客户端激活请求(定时或事件)
    2. JS 对服务器进行 AJAX 调用(可选参数)
    3. 服务器验证任何输入并处理查询
    4. 服务器发回结果
    5. JS 使用结果修改 DOM

    【讨论】:

    • 那么 ajax 调用是否有运行计时器?如果它是一个计时器,那不会有在用户机器上使用内存的副作用吗?
    • 有多种方法可以让 JS 等待做事。为了在计时器上重复做某事,我会选择setInterval(),它需要执行一个函数,并在重复该函数之前等待一个以毫秒为单位的间隔。执行的函数是任意的,但在您的情况下,它将是进行 AJAX 调用的函数。它使用了一些内存,但不是很大,因为它的大部分操作只是检查间隔是否已过,这不是一个巨大的操作,并且在此之前不会调用你给它的函数。
    • 谢谢 - 我会解决这个问题,看看会发生什么。感谢指导。
    • 没问题。如果这回答了您的问题,您应该将其标记为答案,以便其他人知道它已完成。另外,我做了一些小的研究来确认 setInterval 并没有真正消耗太多内存。 Chrome 的时间线模式显然有一个小怪癖,它会报告比实际占用更多的内存,但实际上,如果您没有运行大量的实例,这只是一件很小的事情。
    【解决方案2】:

    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 网络

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-10
      • 2015-09-15
      • 2014-05-05
      • 1970-01-01
      • 2015-06-18
      • 2010-12-29
      • 2021-07-12
      相关资源
      最近更新 更多