对于ajax更新的页面,如何实现离线浏览? 一则方案尝试。

背景

现代页面上越来越多的内容是通过ajax更新, 因为页面可以显示的更加快速, 局部更新, 同时可以实现页面内容的动态性, 增加页面的内容的丰富性。

但是如果将页面内容保存下来, 以备离线浏览器查看, 则由于ajax存在的原因, 直接使用保存的方法不能实现, 因为会有ajax访问禁用的报错。

对于非ajax页面, 页面上内容仅仅使用 链接组织资源的情况, 页面的内容是完整的,  则浏览器保存下来的内容是完整的, 则可以在本地使用离线版本浏览。

方案思路

分析现有页面使用ajax更新的 方法, 有如下两种:

1、 使用ajax方式获取部分html代码, 其中可能有js代码混杂其中, 但是整体上 html代码,  然后使用 jquery.html 接口将 html代码 插入页面中。

  插入过程, 页面html被解析显示, js代码被执行。

2、 使用ajax方式获取页面需要显示的数据, 一般为json格式和xml格式,ajax后去后, 到前台使用js给页面上的指定DOM元素赋值, 获取阻止为到html字符串中, 然后将构造的带有动态数据的html字符串, 插入到DOM节点中。

针对这两种情况, 希望此这两种情况的 数据如果能够存储在当前页面中, 并且重载ajax函数, ajax不去发起http请求, 替换的是从本地的页面中, 查找到缓存的数据, 并返回。那么, ajax调用后的其它部分的代码逻辑没有改变, 不用改动。

只要实现如下内容:

1、 ajax数据的抓取, 并存储到本页面DOM中。

2、 将此页面中使用ajax函数重载为 本地缓存 查找的函数。

3、 将此页面保存为离线文件形式。

然后,你就可以离线浏览了。 当然还有一些链接存在的 文件, 这个不能被保存, 需要另行下载或者准备。 但是被ajax容易多了。

方案实现

借助phantomjs实现抓取和插入DOM, 并修改ajax接口, 并保存为本地文件。

样例

集合 ajax请求html 和 json数据的场景,  顺序为  ajax先请求html文件, html文件中js脚本又发起请求, 请求json文件。

test.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.js"></script>
</head>
<body>
  <img src="./favicon.ico">

  <form id="realform">
  </form>

  <script>
    $(document).ready(function (){
      $.get("./formContent.html", function (data) {
        $("#realform").html(data)
      })
    })
  </script>
</body>
</html>

formContent.html

<input type="text" name="Frm_username" id="Frm_username" value="">
<input type="password" name="Frm_password" id="Frm_password" value="">
<button type="submit">submit</button>

<script>
$(document).ready(function () {
   $.getJSON(‘./test.json‘, function(data) {
    $("#Frm_username").val(data.username);
    $("#Frm_password").val(data.password);
   });
});
</script>

test.json

{
    "username":"fanqingsong",
    "password":"xxxx"
}

PhantomJS 代码

"use strict";

var page = require(‘webpage‘).create();

var fs = require(‘fs‘);
page.open(‘http://localhost/test.html‘, function () {
    page.evaluate(function(){

    });
});

var ajaxURLCode = {};

page.onConsoleMessage = function(msg, lineNum, sourceId) {
  console.log(‘CONSOLE: ‘ + msg + ‘ (from line #‘ + lineNum + ‘ in "‘ + sourceId + ‘")‘);
};

function hereDoc(f) { 
    return f.toString().replace(/^[^\/]+\/\*!?\s?/, ‘‘).replace(/\*\/[^\/]+$/, ‘‘);
}

page.onLoadFinished = function() {
    console.log("page load finished");

    // 待页面ajax内容加载完毕才 截图 和 保存页面内容
    waitFor(function () {
        return page.evaluate(function () {
            if ( $("#Frm_username").val() != "" )
            {
                return true;
            }

            return false;
        });
    }, function  () {
        // 将每个ajax请求的结果记录到当前page 的DOM 中
        for (var urlPath in ajaxURLCode) {
            console.log("====== urlPath="+urlPath);

            var content = ajaxURLCode[urlPath];

            page.evaluate(function(urlPath, content){
                $("<div style=‘display:none‘ id=‘"+urlPath+"‘></div>")
                .text(content)
                .appendTo("body");
            }, urlPath, content);
        };

        // 注入 ajax 请求桩函数, 以实现从页面中缓存显示效果
        page.evaluate(function(hereDoc){
            $("body").prepend("<div id=‘overwriteAjaxFunc‘></div>");

            var ajaxGetRewrite = hereDoc(function () {/*
<script type=‘text/javascript‘>
$(document).ready(function () {
  $.get = function (url, callback) {
     console.log(‘enter $.get refactor‘)
     url = url.match(‘./(.*)‘)[1];
     var data = $(‘[id="‘+url+‘"]‘).text();
     callback(data);
  }

  $.getJSON = function (url, callback) {
     console.log(‘enter $.getJSON refactor‘)
     url = url.match(‘./(.*)‘)[1];
     var data = $(‘[id="‘+url+‘"]‘).text();
     data = JSON.parse(data);
     callback(data);
  }
});
</script>
            */});

            $("#overwriteAjaxFunc").html(ajaxGetRewrite);
        }, hereDoc);

        // 保存页面图片和代码
        page.render(‘test.png‘);
        fs.write(‘test.html‘, page.content, ‘w‘);
    })
};

page.onResourceRequested = function(requestData, networkRequest) {
    // 判断是否为ajax
    var isAjaxRequested = false;
    var headers = requestData.headers;
    for (var i = 0; i < headers.length; i++) {
        var oneHeader = headers[i];
        var headerName = oneHeader.name;
        var headerValue = oneHeader.value;
        if ( headerName == "X-Requested-With"
            && headerValue == "XMLHttpRequest" )
        {
            isAjaxRequested = true;
        }
    }

    // 只记录AJAX请求的结果
    if ( !isAjaxRequested )
    {
        return;
    }

    console.log(‘Request (#‘ + requestData.id + ‘): ‘ + JSON.stringify(requestData));

    var url = requestData.url;
    console.log(" onResourceRequested url="+url)

    if ( url.match("json$") || url.match("html$") )
    {
        var pageRaw = require("webpage").create()
        //pageRaw.settings.javascriptEnabled = false;
        // 借助有jquery的页面 下载 ajax内容
        pageRaw.open(‘http://localhost/test.html‘, function  () {
            console.log("url  =----------------- ="+url)
            //console.log("url plainText ="+pageRaw.plainText)
            //console.log("url content ="+pageRaw.content)

            var content = pageRaw.evaluate(function (url) {
                var ajaxRet = "";

                var request = $.ajax({
                    async: false,
                    url: url,
                    dataType: "text"
                });

                request.done(function( msg ) {
                  ajaxRet = msg;
                });

                console.log("ajaxRet="+ajaxRet)
                return ajaxRet;
            }, url)

            console.log("!!!!!!!!!!!!!content="+content);

            // http://xxx/urlpath
            var matchRet = url.match("http://.*/(.*)")
            console.log("matchRet  =----------------- ="+matchRet)
            var urlPath = matchRet[1]
            console.log("urlPath  =----------------- ="+urlPath)

            ajaxURLCode[urlPath] = content;
        })
    }

};

// page.onResourceReceived = function(response) {
//     //console.log(‘Response (#‘ + response.id + ‘, stage "‘ + response.stage + ‘"): ‘ + JSON.stringify(response));

// };

function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function () {
            if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof (testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if (!condition) {
                    // If condition still not fulfilled (timeout but condition is ‘false‘)
                    console.log("‘waitFor()‘ timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is ‘true‘)
                    console.log("‘waitFor()‘ finished in " + (new Date().getTime() - start) + "ms.");
                    typeof (onReady) === "string" ? eval(onReady) : onReady(); //< Do what it‘s supposed to do once the condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
};

截图

OFFLINE GUI Page Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.js"></script>
</head>
<body><div id="overwriteAjaxFunc">
<script type="text/javascript">
$(document).ready(function () {
  $.get = function (url, callback) {
     console.log(‘enter $.get refactor‘)
     url = url.match(‘./(.*)‘)[1];
     var data = $(‘[id="‘+url+‘"]‘).text();
     callback(data);
  }

  $.getJSON = function (url, callback) {
     console.log(‘enter $.getJSON refactor‘)
     url = url.match(‘./(.*)‘)[1];
     var data = $(‘[id="‘+url+‘"]‘).text();
     data = JSON.parse(data);
     callback(data);
  }
});
</script>
            </div>
  <img src="./favicon.ico">

  <form id="realform"><input type="text" name="Frm_username" id="Frm_username" value="">
<input type="password" name="Frm_password" id="Frm_password" value="">
<button type="submit">submit</button>

<script>
$(document).ready(function () {
   $.getJSON(‘./test.json‘, function(data) {
    $("#Frm_username").val(data.username);
    $("#Frm_password").val(data.password);
   });
});
</script>

</form>

  <script>
    $(document).ready(function (){
      $.get("./formContent.html", function (data) {
        $("#realform").html(data)
      })
    })
  </script>

<div style="display:none" id="formContent.html">&lt;input type="text" name="Frm_username" id="Frm_username" value=""&gt;
&lt;input type="password" name="Frm_password" id="Frm_password" value=""&gt;
&lt;button type="submit"&gt;submit&lt;/button&gt;

&lt;script&gt;
$(document).ready(function () {
   $.getJSON(‘./test.json‘, function(data) {
    $("#Frm_username").val(data.username);
    $("#Frm_password").val(data.password);
   });
});
&lt;/script&gt;

</div><div style="display:none" id="test.json">{
    "username":"fanqingsongaaa",
    "password":"xxxx"
}</div></body></html>
时间: 2024-10-15 13:18:47

对于ajax更新的页面,如何实现离线浏览? 一则方案尝试。的相关文章

学习aiax(javascript)--页面无刷新更新ajax更新时间

1.JSP代码 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"

Ajax回退刷新页面问题的解决办法

在脚本之家看到一篇文章,觉得以后可能会用上,但是竟然不能收藏,所以只能将其转到博客园. 以下是原文地址: http://www.jb51.net/article/87856.htm 这篇文章主要介绍了Ajax回退刷新页面问题的解决办法的相关资料,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧 Ajax 简介: AJAX即"Asynchronous Javascript And XML"(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异

ajax——用ajax写登陆页面

ajax.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="

ajax 如何实现页面跳转

老师,您好.jquery的ajax如何实现页面跳转?例如:登陆页面属于用户名和密码后,点击登陆,验证用户名和密码,正确后,跳转到其他页面.能否给个例子. 下面列了五个例子来详细说明,这几个例子的主要功能是:在5秒后,自动跳转到同目录下的hello.html(根据自己需要自行修改)文件.1) html的实现   123456 优点:简单缺点:Struts Tiles中无法使用 2) javascript的实现 123456 // 以下方式直接跳转window.location.href='hell

struts下ajax提交与页面进行提示 返回值为null

@Override    public String execute() throws Exception {        if ("none".equals(task)) {            HttpServletResponse response = ServletActionContext.getResponse();            response.setContentType("text/html;charset=GBK"); PrintW

jQuery Ajax向某个页面传值并取得返回的数组

本案例讲诉通过Ajax向某个PHP页面传值,并将得到的数组通过json_encode()函数处理,然后返回给ajax,下面是在实际案例摘取的部分代码: PHP页面 public function showChatName(){ $chat = A('Article','Event'); $res = $chat->selectName(I('get.channel')); echo json_encode($res); } 数组$res经过json_encode处理后的输出形式 {"cha

jquery.ajax请求aspx和ashx的异同 Jquery Ajax调用aspx页面方法

1.jquery.ajax请求aspx 请求aspx的静态方法要注意一下问题: (1)aspx的后台方法必须静态,而且添加webmethod特性 (2)在ajax方法中contentType必须是"application/json", (3)data传递的数据必须是严格的json数据,如"{'a':'aa','b':'bb'}",而且参数必须和静态方法的参数一 一对应 (4)aspx的后台方法返回的数据默认形式是"{'d':'返回的内容'}",所

jQuery AJAX实现调用页面后台方法

1.新建demo.aspx页面.2.首先在该页面的后台文件demos.aspx.cs中添加引用. using System.Web.Services; 3.无参数的方法调用. 大家注意了,这个版本不能低于.net framework 2.0.2.0已下不支持的.后台代码: [WebMethod] public static string SayHello() { return "Hello Ajax!"; } JS代码: $(function() { $("#btnOK&qu

Jquery Ajax调用aspx页面方法

原文:Jquery Ajax调用aspx页面方法 在asp.net webform开发中,用jQuery ajax传值一般有几种玩法 1)普通玩法:通过一般处理程序ashx进行处理: 2)高级玩法:通过aspx.cs中的静态方法+WebMethod进行处理: 3)文艺玩法:通过WCF进行处理. 第一种和第三种方法不在本文介绍范围之内,下面重点介绍第二种方法. 说明 在我们的印象里 asp.net的Web服务是以.asmx来结尾的,而我们现在的asp.net也能实现Web服务,这是因为默认Web.