使用jQuery获取JSON文件而无需Web服务器

7

我参加了一次前端编码的面试测试,主题涉及JSON等IT技术。我提交了我的文件,但我想了解我错过了什么。

其中一个要求是不应该需要Web服务器,并且应该能够离线运行

我使用了jQuery 并使用 $.getJSON().JSON 文件获取数据。我将其放在我的WAMP本地服务器上,并且它在所有三个主流浏览器(IE,Firefox,Chrome)上完美运行。然后,我将该项目移动到桌面上,实际上没有使用LOCALSERVER。

在Firefox 30.0上,它非常好用。没有问题。

在Google Chrome上,我知道你不能在没有Web服务器的情况下访问本地文件...

然而,在Internet Explorer 11上,它却无法工作。为什么?

这是我正在使用的内容。它并不复杂。

function loadTasks() {
  console.log("Loading tasks...");
  $.getJSON("data.json", function(result) {
    $.each(result, function(i, task) {
      $("#load_tasks").append(
        "<div class='row'><span class='data-task'>" + task.name +
        "</span> <span class='data-date'>" + task.date +
        "</span> <span class='data-name'>" + task.assigned +
        "</span> </div>");
    });
  });
}

and here is data.json


@SuperHornet在IE中不行。 - test
没有任何内容... @SuperHornet - test
你使用的是哪个版本的jQuery? - MIdhun Krishna
2
还要进入“Internet选项”>“高级”选项卡,勾选“允许在我的计算机上运行Active内容”。您能回复一下这个操作的结果吗? - MIdhun Krishna
1
nyro.net/data.json不存在... - Kai Hartmann
显示剩余5条评论
10个回答

6
这似乎是jQuery中的一个错误。该错误已报告给jQuery。错误状态已修复。但是似乎该错误仍然存在。
解释:
通常在IE中,ajax是通过ActiveXObjects实现的。但在IE11中,他们对ActiveXObject实现进行了一些调整,如果我们尝试执行以下操作:
typeof(window.ActiveXObject)

与其返回“function”,正如IE文档中所说的那样,它返回undefined。jQuery曾经使用这个方法在普通浏览器和IE之间切换xhr。由于检查结果为undefined,因此在普通浏览器中运行用于创建xhr对象的代码。(当然,对于非本地文件,它能够正常工作,这显然是一个错误)。

提交到bugs.jquery.com的错误报告中,错误报告人员问道,

为了解决问题,只需更改条件:使用"window.ActiveXObject !== undefined ?"而不是"window.ActiveXObject ?"

jQuery开发人员尝试通过这个提交来解决这个问题,但提交下的评论表示仍然没有解决,并提出了可能解决该问题的方法。

var activex; // save activex somewhere so that it only need to check once
if ( activex === undefined ) 
  try { 
    new ActiveXObject("MSXML2.XMLHTTP.3.0");
    activex = true; 
  } catch (e) { 
    activex = false 
  }
xhr = activex ? createActiveXHR() : createStandardXHR(); 

在执行此操作时,我收到了“createActiveXHR()未定义”的错误信息。 - test

3

我在我的计算机上尝试运行您的代码,在IE中运行良好。 然而,如果在您的计算机上无法运行,可能是IE设置存在问题。除此之外,如果您想读取本地文件,可以尝试以下代码来解决IE的问题

function showData(){
function getLocalPath(fileName/*file name assuming in same directory*/){
    // Remove any location or query part of the URL
    var directoryPath = window.location.href.split("#")[0].split("?")[0];
    var localPath;
    if (directoryPath.charAt(9) == ":") {
        localPath = unescape(directoryPath.substr(8)).replace(new RegExp("/","g"),"\\");
    }
    localPath = localPath.substring(0, localPath.lastIndexOf("\\")+1)+fileName;
    console.log(localPath);
    return localPath;
}

var content = null;
    try {
        var fileSystemObj = new ActiveXObject("Scripting.FileSystemObject");
        var file = fileSystemObj.OpenTextFile(getLocalPath("data.json"),1);
        content = file.ReadAll();
        file.Close();
    } catch(ex) {
        console.log(ex);
    }
    console.log(content);
}
showData();

从文件路径在浏览器中运行您的html文件,并尝试在控制台中运行上面的函数。它将输出json文件的内容到控制台。

您可以创建一个包装器来使用XHR请求中的上述代码。如果需要将其与jQuery AJAX请求集成,请告诉我需要帮助。


1
更新代码以展示如何正确地给出文件路径。 - khagesh

1
你所缺少的是使用appCache技术。
<html manifest="example.appcache">

在你的HTACCESS文件中添加。
AddType text/cache-manifest .appcache

在example.appcache内部。
CACHE MANIFEST
data.json
index.php
someimage.png
# continue for all the file needed for the web site to work

这意味着一旦你连接并下载了内容,它就不再需要了。另外,你不能通过XHR/ajax访问file:// URI,因为没有办法发送内容。如果你想要离线访问,你可以将json文件的内容嵌入代码中作为字符串,并使用var jsonStr = '{}'; var jsonObj = JSON.parse(jsonStr);,其中jsonStr是你的代码。这样就不需要与服务器建立连接,也不需要ajax/XHR请求。

1

jQuery的 .getJSON 使用ajax。http://api.jquery.com/jquery.getjson/

.ajax 使用XMLHttpRequest。

Chrome和其他浏览器的Web安全会阻止XMLHttpRequest访问本地文件,因为这是一个安全问题。

通过深度安全:本地网页

http://blog.chromium.org/2008/12/security-in-depth-local-web-pages.html

您收到了一封带有网页附件的攻击者发送的电子邮件,您下载了该附件。

您在浏览器中打开了现在的本地网页。

本地网页创建了一个iframe,其源是https://mail.google.com/mail/

由于您已登录 Gmail,因此该框架会加载收件箱中的邮件。

本地网页使用JavaScript访问frames[0].document.documentElement.innerHTML读取框架的内容。(互联网网页无法执行此步骤,因为它来自非Gmail来源;同源策略将导致读取失败。)

本地网页将您的收件箱内容放入一个<textarea>中,并通过表单POST向攻击者的Web服务器提交数据。现在,攻击者拥有了您的收件箱,这可能对垃圾邮件或身份盗窃有用。

对于不需要同源策略安全的数据,解决方案是填充json。因为jsonp不是一种安全的数据格式。jsonp没有同源策略。

/* secured json */
{
  "one": "Singular sensation",
  "two": "Beady little eyes",
  "three": "Little birds pitch by my doorstep"
}

/* padded json aka jsonp */
Mycallback ({
  "one": "Singular sensation",
  "two": "Beady little eyes",
  "three": "Little birds pitch by my doorstep"
});

由于jsonp将json封装在一个有效的javascript函数中,因此可以像添加任何javascript到页面一样打开它。
var element = document.createElement("script");
element.src = "jsonp.js";
document.body.appendChild(element);

你的回调函数处理数据,
function Mycallback(jsondata) {
}

这与ajax请求在功能上基本相同,但不同之处在于它是一个jsonp请求,实际上更容易。
jQuery库也直接支持jsonp http://api.jquery.com/jquery.getjson/。请参考使用Flickr的JSONP API的示例;除非知道这种双重标准,否则可能甚至不会注意到正在使用jsonp。
(function() { /* jsonp request note callback in url, otherwise same json*/
  var flickerAPI = "http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?"; 
  $.getJSON( flickerAPI, {
    tags: "mount rainier",
    tagmode: "any",
    format: "json"
  })
    .done(function( data ) {
      $.each( data.items, function( i, item ) {
        $( "<img>" ).attr( "src", item.media.m ).appendTo( "#images" );
        if ( i === 3 ) {
          return false;
        }
      });
    });
})();

本地访问json是可以启用的,但不同浏览器的操作方式不同。
在Chrome中使用--allow-file-access-from-files进行启用。https://code.google.com/p/chromium/issues/detail?id=40787 FYI:他们正在开发加密JSONhttps://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-encryption-08。我相当确定不会有本地使用的方法,意图是使其非常安全。

这是一个很好的答案示例,但你忘记了一件事,jsonp永远无法被缓存,因为jQuery会即时创建函数名称,所以内容在不断变化,这将阻止其离线使用。而且我怀疑面试官希望他改变浏览器启动参数来运行代码,这有点违背Web应用程序的初衷,如果人们必须更改浏览器启动选项才能使用它... - Barkermn01

0

使用JSONP,您可以使此功能适用于所有浏览器,无论是否有Web服务器甚至跨域。

示例data.jsonp文件:

loadTasks([
    {name:"Task 1", date:"Date 1", assigned:"John Doe"},
    {name:"Task 2", date:"Date 2", assigned:"Jane Doe"}
]);

然后在您的页面上,只需使用脚本标签加载data.jsonp:

<script>
function loadTasks(tasks) {
    $.each(tasks, function (i, task) {
        $("#load_tasks").append(
            "<div class='row'><span class='data-task'>" + task.name +
            "</span> <span class='data-date'>" + task.date +
            "</span> <span class='data-name'>" + task.assigned +
            "</span> </div>");
    });  
}
</script>
<script src="data.jsonp"></script>

0

尝试包含一个error回调函数; jqxhr.responseText可能仍然包含data.json

data.json

{"data":{"abc":[123]}}

json.html

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
<script type="text/javascript">
$(function() {
  $.getJSON(document.location.protocol + "data.json")
  .then(function(data, textStatus, jqxhr) {
    var response = JSON.parse(data);
    console.log(textStatus, response);
  } 
   // `error` callback
  , function(jqxhr, textStatus, errorThrown) {
      var response = JSON.parse(jqxhr.responseText);
      console.log(textStatus, errorThrown, response);
      $("body").append(response.data.abc);
  });
})
</script>
</head>
<body>
</body>
</html>

0

来源: https://stackoverflow.com/a/22368301/1845953

我发表这个答案是为了以防其他人遇到同样的问题。在我的情况下,IE加载了一个似乎导致"JSON未定义"错误的jquery版本。以下是我解决这个问题的方法:

<!--[if lt IE 9]>
    <script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
    <script src="http://code.jquery.com/jquery-2.0.3.js"></script>
<!--<![endif]-->

最新版本是 jquery 2.1.1直链 但它说:

(IE <9 不支持)

所以我猜 jquery 1.11.1直链

并且我发现如果使用此标志的 Chrome: --allow-file-access-from-files (来源),您可以在本地文件中开发 ajax 和 jquery。

如果您使用CDN源文件,将无法在离线状态下工作。 - charlietfl

0
<meta http-equiv="X-UA-Compatible" content="IE=edge"> 

尝试添加这个元标签并在IE中检查


不是的。我明白它在做什么。 - test

0
这是一个可行的解决方案。 我包含了handlebars,因为它更加简洁。
<!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>JSON TEST</title>

    </head>
    <body>

        <div id="load-tasks">

        </div>


        <script src="jquery.min.js"></script>
        <script src="handlebars.min.js"></script>


        <script id="tasks-template" type="text/x-handlebars-template">
            {{#each .}}
            <div class="row">
                <span class="data-task">
                    {{this.name}}
                </span> <span class="data-date">
                    {{this.date}}
                </span> <span class="data-name">
                    {{this.assigned}}
                </span>
            </div>
            {{/each}}
        </script>

        <script>
            $(function () {
                var loadTasksContainer = $('#load-tasks'),
                    tasksTemplate = Handlebars.compile($('#tasks-template').html());

                $.ajax({
                    type: "GET",
                    url: "data.json",
                    dataType: "json",
                    cache: false,                    
                    success: function (data) {
                        var html = tasksTemplate(data);
                        loadTasksContainer.append(html);
                    },
                    error: function (xhr, status, error) {
                        //log error and status
                    }
                });

            });
        </script>
    </body>
    </html>

0

处理这个问题将带领你走向任何地方。这是一项困难的任务,但可以轻松使用任何http服务器解决。

如果你的问题在于很难设置一个http服务器,可以尝试使用以下方法: https://www.npmjs.org/package/http-server

在你的shell中,进入存放文件的目录,然后只需输入以下命令:

http-server ./ -p 12345 

其中12345可以被您选择的任何有效且未使用过的端口替换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接