页面实现长连接

基于HTTP的长连接,是一种通过长轮询方式实现”服务器推”的技术,它弥补了HTTP简单的请求应答模式的不足,极大地增强了程序的实时性和交互性。

长连接、长轮询:都是通过不断的向服务器发出请求,如果服务器有数据则马上返回,如果没有数据就会hold住请求,等到有数据的时候就推送给页面。

通常的做法是,在服务器的程序中加入一个死循环,在循环中监测数据的变动。当发现新数据时,立即将其输出给浏览器并断开连接,浏览器在收到数据后,再次发起请求以进入下一个周期,这就是常说的长轮询(long-polling)方式。如下图所示,它通常包含以下几个关键过程:

这里写图片描述
服务端的代码如下:

@RequestMapping("/ajax")
public void ajax(long timed, HttpServletResponse response) throws Exception {
     PrintWriter writer = response.getWriter();

     Random rand = new Random();
     // 死循环 查询有无数据变化
     while (true) {
         Thread.sleep(300); // 休眠300毫秒,模拟处理业务等
         int i = rand.nextInt(100); // 产生一个0-100之间的随机数
         if (i > 20 && i < 56) { // 如果随机数在20-56之间就视为有效数据,模拟数据发生变化
             long responseTime = System.currentTimeMillis();
             // 返回数据信息,请求时间、返回数据时间、耗时
             writer.print("result: " + i + ", response time: " + responseTime + ", request time: " + timed + ", use time: " + (responseTime - timed));
             break; // 跳出循环,返回数据
         } else { // 模拟没有数据变化,将休眠 hold住连接
             Thread.sleep(1300);
         }
     }

}

下面主要介绍几种页面发起请求的方式:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="author" content="hoojo & http://hoojo.cnblogs.com">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>

        <script type="text/javascript">
            $(function () {

                window.setInterval(function () {

                    $.get("${pageContext.request.contextPath}/communication/user/ajax.mvc", 
                        {"timed": new Date().getTime()}, 
                        function (data) {
                            $("#logs").append("[data: " + data + " ]<br/>");
                    });
                }, 3000);

            });
        </script>
    </head>

    <body>
        <div id="logs"></div>
    </body>
</html>

客户端实现的就是用一种普通轮询的结果,比较简单。利用setInterval不间断的刷新来获取服务器的资源,这种方式的优点就是简单、及时。缺点是链接多数是无效重复的;响应的结果没有顺序(因为是异步请求,当发送的请求没有返回结果的时候,后面的请求又被发送。而此时如果后面的请求比前面的请求要先返回结果,那么当前面的请求返回结果数据时已经是过时无效的数据了);请求多,难于维护、浪费服务器和网络资源。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>

        <script type="text/javascript">
            $(function () {

                window.setInterval(function () {
                    $("#logs").append("[data: " + $($("#frame").get(0).contentDocument).find("body").text() + " ]<br/>");
                    $("#frame").attr("src", "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime());
                    // 延迟1秒再重新请求
                    window.setTimeout(function () {
                        window.frames["polling"].location.reload();
                    }, 1000);
                }, 5000);

            });
        </script>
    </head>

    <body>
        <iframe id="frame" name="polling" style="display: none;"></iframe>
        <div id="logs"></div>
    </body>
</html>

这里的客户端程序是利用隐藏的iframe向服务器端不停的拉取数据,将iframe获取后的数据填充到页面中即可。同ajax实现的基本原理一样,唯一不同的是当一个请求没有响应返回数据的情况下,下一个请求也将开始,这时候前面的请求将被停止。如果要使程序和上面的ajax请求一样也可以办到,那就是给每个请求分配一个独立的iframe即可。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="author" content="hoojo & http://hoojo.cnblogs.com">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <%@ include file="/tags/jquery-lib.jsp"%>

        <script type="text/javascript">
            $(function () {

                window.setInterval(function () {
                    var url = "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime();
                    var $iframe = $('<iframe id="frame" name="polling" style="display: none;" src="' + url + '"></iframe>');
                    $("body").append($iframe);

                    $iframe.load(function () {
                        $("#logs").append("[data: " + $($iframe.get(0).contentDocument).find("body").text() + " ]<br/>");
                        $iframe.remove();
                    });
                }, 5000);

            });
        </script>
    </head>

    <body>

        <div id="logs"></div>
    </body>
</html>

这个轮询方式就是把刚才上面的稍微改下,每个请求都有自己独立的一个iframe,当这个iframe得到响应的数据后就把数据push到当前页面上。使用此方法已经类似于ajax的异步交互了,这种方法也是不能保证顺序的、比较耗费资源、而且总是有一个加载的条在地址栏或状态栏附件

如果想要保住顺序,可以不使用setInterval,将创建iframe的方法放在load事件中即可,即使用递归方式:

<script type="text/javascript">
    $(function () {
        (function iframePolling() {
            var url = "${pageContext.request.contextPath}/communication/user/ajax.mvc?timed=" + new Date().getTime();
            var $iframe = $('<iframe id="frame" name="polling" style="display: none;" src="' + url + '"></iframe>');
            $("body").append($iframe);

            $iframe.load(function () {
                $("#logs").append("[data: " + $($iframe.get(0).contentDocument).find("body").text() + " ]<br/>");
                $iframe.remove();

                // 递归
                iframePolling();
            });
        })();    
    });
</script>

这种方式虽然保证了请求的顺序,但是它不会处理请求延时的错误或是说很长时间没有返回结果的请求,它会一直等到返回请求后才能创建下一个iframe请求,总会和服务器保持一个连接。和以上轮询比较,缺点就是消息不及时,但保证了请求的顺序。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %>
<% 
String path = request.getContextPath(); 
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 
%> 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <meta http-equiv="pragma" content="no-cache">
        <meta http-equiv="cache-control" content="no-cache">
        <meta http-equiv="expires" content="0">
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script src="<%=path%>/js/jquery-1.9.1.min.js" type="text/javascript"></script> 

        <script type="text/javascript">
            $(function () {

                (function longPolling() {

                    $.ajax({
                        url: "http://localhost:8080/web/testServlet",
                        data: {"timed": new Date().getTime()},
                        dataType: "text",
                        timeout: 5000,
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            $("#state").append("[state: " + textStatus + ", error: " + errorThrown + " ]<br/>");
                            if (textStatus == "timeout") { // 请求超时
                                longPolling(); // 递归调用
                                 // 其他错误,如网络错误等
                            } else { 
                                longPolling();
                            }
                        },
                        success: function (data, textStatus) {
                            $("#state").append("[state: " + textStatus + ", data: { " + data + "} ]<br/>");
                            if (textStatus == "success") { // 请求成功
                                longPolling();
                            }
                        }
                    });
                })();
            });
        </script>
    </head>

    <body>
        <div id="state"></div>
    </body>
</html>

上面这段代码就是才有Ajax的方式完成长连接,主要优点就是和服务器始终保持一个连接。如果当前连接请求成功后,将更新数据并且继续创建一个新的连接和服务器保持联系。如果连接超时或发生异常,这个时候程序也会创建一个新连接继续请求。这样就大大节省了服务器和网络资源,提高了程序的性能,从而也保证了程序的顺序。这种方法是最好使用的。

总结:
现代的浏览器都支持跨域资源共享(Cross-Origin Resource Share,CORS)规范,该规范允许XHR执行跨域请求,因此基于脚本的和基于iframe的技术已成为了一种过时的需要。
把Comet做为反向Ajax的实现和使用的最好方式是通过XMLHttpRequest对象,该做法提供了一个真正的连接句柄和错误处理。当然你选择经由HTTP长轮询使用XMLHttpRequest对象(在服务器端挂起的一个简单的Ajax请求)的Comet模式,所有支持Ajax的浏览器也都支持该种做法。
基于HTTP的长连接技术,是目前在纯浏览器环境下进行即时交互类应用开发的理想选择,随着浏览器的快速发展,HTML5将为其提供更好的支持和更广泛的应用。在Html5中有一个websocket 可以很友好的完成长连接这一技术,网上也有相关方面的资料,这里也就不再做过多介绍。
程序的代码示例:https://github.com/lichencai/prjTest/tree/master/src/longconnect

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 你可以使用 Vue.js 和 WebSocket 实现页面实时刷新。 首先,在你的 Vue 组件中创建一个 WebSocket 对象: ``` let socket = new WebSocket('ws://your-websocket-server'); ``` 然后,添加一个监听器来处理服务器发送的消息: ``` socket.onmessage = function (event) { // 处理服务器发送的消息 } ``` 当你的 Vue 组件中的数据发生变化时,你可以使用 WebSocket 向服务器发送消息: ``` socket.send(JSON.stringify({ // 发送的数据 })); ``` 最后,在组件销毁时,记得关闭 WebSocket 连接: ``` beforeDestroy() { socket.close(); } ``` 希望这些信息能帮到你! ### 回答2: Vue WebSocket 实现页面实时刷新长连接的过程如下: 首先,需要在Vue项目中安装WebSocket库。可以使用npm安装vue-native-websocket库,该库提供了适用于Vue的WebSocket模块。通过运行`npm install vue-native-websocket`命令进行安装。 安装完成后,在Vue项目的入口文件main.js中导入WebSocket库。通过以下代码实现: ```javascript import VueNativeSock from 'vue-native-websocket' Vue.use(VueNativeSock, 'ws://localhost:8080', { reconnection: true, // 是否自动重新连接 reconnectionAttempts: 5, // 重新连接次数 reconnectionDelay: 3000, // 重新连接延迟时间,单位ms }) ``` 这里通过Vue.use()方法将WebSocket库注册到Vue应用中,并指定连接的URL以及一些配置项,如是否自动重新连接、重新连接次数和延迟时间。 接下来,在Vue组件中使用WebSocket。可以在created()生命周期钩子函数中创建WebSocket连接。可以通过以下代码实现: ```javascript export default { created() { this.$options.sockets.onmessage = (data) => { // 接收到消息时的处理逻辑 // 刷新页面或做其他操作 } }, // ... } ``` 这里通过设置this.$options.sockets.onmessage回调函数,当接收到WebSocket服务器发送的消息时,该函数中的逻辑将被执行。在该函数中可以实现页面的实时刷新或其他操作。 最后,需要在WebSocket服务器端实现消息的发送。根据具体的服务器端实现方式,可以使用相应语言和框架提供的WebSocket库,将消息发送给连接的客户端。 总结起来,Vue WebSocket 实现页面实时刷新长连接的过程包括:安装WebSocket库、在入口文件中注册WebSocket模块、在组件中使用WebSocket并处理接收到的消息、在服务器端实现消息的发送。通过这些步骤,便可以在Vue应用中实现WebSocket长连接,并根据接收到的消息实现页面的实时刷新。 ### 回答3: Vue WebSocket 可以实现页面实时刷新长连接,具体步骤如下: 1. 首先,在 Vue 项目中安装 WebSocket 插件。 2. 在需要实时刷新的页面或组件中,引入 WebSocket 并创建连接。 3. 创建 WebSocket 连接后,可以监听连接的状态,比如打开、关闭、错误等。 4. 使用 WebSocket 的 onmessage 事件监听服务器发送的消息,一旦收到消息,即可触发页面或组件的刷新操作。 5. 可以通过 WebSocket 的 send 方法向服务器发送消息,实现与服务器的双向通信。 6. 在页面或组件销毁时,记得关闭 WebSocket 连接以避免资源浪费。 总结起来,Vue WebSocket 实现页面实时刷新长连接的步骤包括安装插件、创建连接、监听连接状态、监听服务器发送消息、发送消息以及关闭连接。这样可以实现页面与服务器的实时双向通信,达到页面实时刷新的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值