如何使用JavaScript从另一个服务器获取数据?

24

如何使用用户浏览器中的JavaScript向其他服务器发出请求(即从任意所需服务器获取页面)?对于像XMLHttpRequest这样的方法,存在限制以防止此类操作,是否有绕过它们或其他方法的方式?

这是一个通用问题,具体而言,我想检查一系列随机网站并查看它们是否包含某个元素,因此我需要网站的HTML内容,而不需要下载任何其他文件;所有这些都在JavaScript文件中实现,没有使用服务器上的转发或代理机制

(注:一种方法是使用Greasemonkey及其GM_xmlhttpRequest。)


3
你需要服务器端代码来完成这个任务,跨域请求存在安全漏洞,而且即使你费尽心思地想要解决这种情况,也很难实现。不应该这样做。使用简单的后端语言如PHP或者像Sinatra这样的框架就可以了。 - rfunduk
8个回答

25

你应该查看jQuery。它有丰富的AJAX功能,可以让你拥有这些能力。你可以加载外部页面,并使用直观的CSS选择器解析其HTML内容。

一个使用$.get();的例子:

$.get("anotherPage.html", {}, function(results){
  alert(results); // will show the HTML from anotherPage.html
  alert($(results).find("div.scores").html()); // show "scores" div in results
});

对于外部域名,我必须编写一个本地PHP脚本作为中间人。jQuery将调用本地PHP脚本,并将另一个服务器的URL作为参数传递,本地PHP脚本将收集数据,然后jQuery将从本地PHP脚本读取数据。

$.get("middleman.php", {"site":"http://www.google.com"}, function(results){
  alert(results); // middleman gives Google's HTML to jQuery
});

middleman.php 一些类似的东西

<?php

  // Do not use as-is, this is only an example.
  // $_GET["site"] set by jQuery as "http://www.google.com"
  print file_get_contents($_GET["site"]);

?>

@mmattax,请检查我的最后一段。 - Sampson
你提到了“在某些情况下” - 那么其他情况是什么?(注意:我已更新问题,排除中间人服务器脚本。) - user46665
2
@petersidor,有些网站不允许来自其他域的JavaScript进行任何访问。因此,您需要使用file_get_contents()或其他类似的方法来获取它们的HTML。 - Sampson
@Jonathan:更正一下,没有网站允许其他[顶级]域名的JavaScript访问权限。 - Crescent Fresh
这看起来是一个对于一般问题可以接受的解决方案,所以我给它点了赞;不幸的是它并没有完全涵盖我的特定问题,因此我不能将其标记为最终解决方案。 - user46665
显示剩余4条评论

5

更新2018年:

您只能通过以下4个条件访问跨域:

  • 在响应头中有Access-Control-Allow-Origin: *

Demo

$.ajax({
  url: 'https://api.myjson.com/bins/bq6eu',
  success: function(response){
    console.log(response.string);
  },
  error: function(response){
    console.log('server error');
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

  • 使用服务器作为桥接或代理到目标

演示:

$.ajax({
  url: 'https://cors-anywhere.herokuapp.com/http://whatismyip.akamai.com/',
  success: function(response){
    console.log('server IP: ' + response);
  },
  error: function(response){
    console.log('bridge server error');
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

  • 使用浏览器插件启用Allow-Control-Allow-Origin: *
  • 禁用浏览器Web安全性

Chrome

chrome.exe --args --disable-web-security

火狐浏览器

about:config -> security.fileuri.strict_origin_policy -> false

结束


2011年的菜鸟老回答

$.get()可以从jsbin.com获取数据,但我不知道为什么它无法从另一个网站(如google.com)获取数据。

$.get('http://jsbin.com/ufotu5', {},
  function(results){  alert(results); 
});

演示:http://jsfiddle.net/Xj234/ 在Firefox、Chrome和Safari中进行了测试。


3
编写一个代理脚本,将来自您域的http请求转发,这将绕过XMLHttpRequest限制。
如果您使用PHP,只需使用cURL请求和读取页面,然后将HTML作为来自您域的内容输出即可。

3
这很容易...如果你知道几乎没有人分享的“秘密”技巧。
它叫做Yahoo yql...
所以为了重获“用户的权力”(并回到方便的口号:“永远不接受‘不’”),只需使用http://query.yahooapis.com/(而不是php?代理服务器端脚本)。 jQuery不是必需的。 示例1:
使用类似SQL的命令:
select * from html 
where url="http://stackoverflow.com" 
and xpath='//div/h3/a'

以下链接将会从SO上爬取最新的问题(绕过跨域安全限制):
http://query.yahooapis.com/v1/public/yql?q=select%20title%20from%20html%20where%20url%3D%22http%3A%2F%2Fstackoverflow.com%22%20and%0A%20%20%20%20%20%20xpath%3D%27%2F%2Fdiv%2Fh3%2Fa%27%0A%20%20%20%20&format=json&callback=cbfunc

正如您所看到的,这将返回一个JSON数组(也可以选择XML),并调用回调函数:cbfunc

实际上,每当您不需要从“标签混乱”中提取数据时,您还可以拯救一只小猫咪

你能听到内心的小疯子开始咯咯笑了吗?

如果想要了解更多信息,请参见此答案(别忘了评论区有更多示例)。

祝好运!


1
此服务已经停用,请参见 https://dev59.com/zFQJ5IYBdhLWcg3wWkf9。 - Nathan

1

你也可以使用 iframe 来模拟一个 ajax 请求。这样可以避免为前端问题编写后端解决方案的混乱。以下是一个示例:

function setUploadEvent(typeComponet){
       var eventType = "";
       var iframe = document.getElementById("iframeId");
       try{
           /* for Mozilla / Opera9 */
           if (/(?!.*?compatible|.*?webkit)^mozilla|opera/i.test(navigator.userAgent)) {
                eventType = "onload";
           }else{
           /* IE  */
                eventType = "onreadystatechange";
           }

           iframe[eventType] = function(){
                var doc = iframe.contentDocument || iframe.contentWindow.document;
                var response = doc.body.innerHTML; /* or what ever content you are looking for */
             }
           }
       catch(e){
           alert("Error loading content")}
       } 

应该就可以了。请注意,浏览器检测代码并不是最干净的,你应该绝对使用所有常见JS框架(Prototype、JQuery等)中提供的代码。


现在看起来更像样了 - 我会试一下并回报结果,我已经投票支持了。它可能看起来很粗糙,但有时候,简单确实更好。 :) - user46665
尝试过了,不幸的是浏览器不允许访问来自不同服务器的网站的iframe属性。所以这基本上与XMLHttpRequest的问题相同,看起来我的问题是不可能解决的。 :| - user46665

0

非常感谢,这真的是一个好技巧。我是这样做的:

test.html

<!DOCTYPE html>
<html>
<head>
<script>
function loadXMLDoc()
{
if (window.XMLHttpRequest)
  {// code for IE7+, Firefox, Chrome, Opera, Safari
  xmlhttp=new XMLHttpRequest();
  }
else
  {// code for IE6, IE5
  xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
xmlhttp.onreadystatechange=function()
  {
  if (xmlhttp.readyState==4 && xmlhttp.status==200)
    {
    document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
  }
xmlhttp.open("GET","sp.php",true);
xmlhttp.send();
}
</script>
</head>
<body>

<h2>Using the XMLHttpRequest object</h2>
<div id="myDiv"></div>
<button type="button" onclick="loadXMLDoc()">Change Content</button>

</body>
</html>

sp.php

<?php
  print file_get_contents("http://your.url.com/you-can-use-cross-domain");
?>

0

<script language="JavaScript" type="text/javascript" src="http://www.example.com/hello.js"></script>

你可以将数据以数组、JSON或类似的形式添加到hello.js中。例如: var daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

从另一个服务器获取JavaScript并不复杂.. :-)


想要用JavaScript脚本从另一个服务器获取数据,但这很有趣。 :) - user46665
请查看我的更新,了解如何向外部JavaScript添加数据。 - Kristoffer Bohmann
抱歉,我的问题不够清晰,我已经更新了它 - 目的是从服务器获取数据 - 比如整个HTML页面,并在用户浏览器中运行的JavaScript中访问它。 - user46665

0
你需要在服务器上编写代理来完成这个任务。所有请求都将发送到你的服务器,然后你的服务器将加载HTML并将其发送回客户端。没有很好的方法仅通过JavaScript实现这一点。
jQuery包含使用XmlHttpRequest加载JSON数据或外部脚本的功能,但是此功能不能用于HTML页面。另外,你可以查看jQuery邮件列表中的this thread

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