今天来记录一下关于ajax跨域的一些问题。以备不时之需。

跨域

同源策略限制

同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性。也就是说,受到请求的 URL 的域必须与当前 Web 页面的域相同。这意味着浏览器隔离来自不同源的内容,以防止它们之间的操作。

解决方式

通常来说,比较通用的有如下两种方式,一种是从服务器端下手,另一种则是从客户端的角度出发。二者各有利弊,具体要使用哪种方式还需要具体的分析。

  1. 服务器设置响应头
  2. 服务器代理
  3. 客户端采用脚本回调机制。

方式一

Access-Control-Allow-Origin 关键字只有在服务器端进行设置才
会生效。也就是说即使再客户端使用

xmlhttprequest.setHeaderREquest('xx','xx');

也不会有什么效果。

正常ajax请求

下面来模拟一下ajax非跨域请求的案例实现。

test1.html

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>ajax 测试</title>
</head>
<body>

<input type="button" value="Test" onclick="crossDomainRequest()">
<div id="content"></div>
<script>
 var xhr = new XMLHttpRequest();
 var url = 'http://localhost/learn/ajax/test1.php';

 function crossDomainRequest() {
  document.getElementById('content').innerHTML = "<font color='red'>loading...</font>";
  // 延迟执行
  setTimeout(function () {
   if (xhr) {
    xhr.open('GEt', url, true);
    xhr.onreadystatechange = handle_response;
    xhr.send(null);
   } else {
    document.getElementById('content').innerText = "不能创建XMLHttpRequest对象";
   }
  }, 3000);
 }

 function handle_response() {
  var container = document.getElementById('content');
  if (xhr.readyState == 4) {
   if (xhr.status == 200 || xhr.status == 304) {
    container.innerHTML = xhr.responseText;
   } else {
    container.innerText = '不能跨域请求';
   }
  }
 }
</script>

</body>
</html>

同级目录下的test1.PHP内容如下:

<?php

echo "It Works.";

?>

正常ajax请求

跨域请求

刚才是HTML文件和php文件都在Apache的容器下,所以没有出现跨域的情形,现在把HTML文件放到桌面上,这样再次请求PHP数据的话,就营造了这样一个“跨域请求”了。

注意看浏览器的地址栏信息

再次进行访问,发现会出现下面的错误信息。

跨域出现了问题

针对这种情况,比较常见的一个操作就是设置Access-Control-Allow-Origin。

格式: Access-Control-Allow-Origin: domain.com/xx/yy.*

如果知道客户端的域名或者请求的固定路径,则最好是不使用通配符的方式,来进一步保证安全性。如果不确定,那就是用*通配符好了。

后端开发语言为PHP的时候可以再文件开始处这么设置:

header("Access-Control-Allow-Origin: *");

如果是ASPX页面的话,要这么设置(Java与之类似):

Response.AddHeader("Access-Control-Allow-Origin", "*");

这时,再次来访问一下刚才的路径。

服务器端跨域设置

服务器代理模式

这种方式应该算是比较常用的,而且被广泛采纳的一个方式了。说代理有点太过于书面化了,其实就是传话儿的。来举个小例子:

小明喜欢三班一个叫小红的女孩儿,但是不好意思去要人家的QQ,微信号。然后就托和自己班的女生–小兰。来帮自己去要。所以小兰就相当于一个代理。帮助小明获取原本不能直接获取的小红的联系方式。

下面来举个例子说明这个问题。

直接的跨域请求

修改一下刚才的URL即可,让ajax直接去请求其他网站的数据。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>ajax 测试</title>
</head>
<body>

<input type="button" value="Test" onclick="crossDomainRequest()">
<div id="content"></div>
<script>
 var xhr = new XMLHttpRequest();
// var url = 'http://localhost/learn/ajax/test1.php';
  var url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=哒哒';
 function crossDomainRequest() {
  document.getElementById('content').innerHTML = "<font color='red'>loading...</font>";
  // 延迟执行
  setTimeout(function () {
   if (xhr) {
    xhr.open('GEt', url, true);
    xhr.onreadystatechange = handle_response;
    xhr.send(null);
   } else {
    document.getElementById('content').innerText = "不能创建XMLHttpRequest对象";
   }
  }, 3000);
 }

 function handle_response() {
  var container = document.getElementById('content');
  if (xhr.readyState == 4) {
   if (xhr.status == 200 || xhr.status == 304) {
    container.innerHTML = xhr.responseText;
   } else {
    container.innerText = '不能跨域请求';
   }
  }
 }
</script>

</body>
</html>

结果如下:

代理模式下直接跨域会失败

启用代理模式

刚才的HTML页面,咱们还是用自己的接口:

url = 'http://localhost/learn/ajax/test1.php';

具体如下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>ajax 测试</title>
</head>
<body>

<input type="button" value="Test" onclick="crossDomainRequest()">
<div id="content"></div>
<script>
 var xhr = new XMLHttpRequest();
 var url = 'http://localhost/learn/ajax/test1.php';
//  var url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=哒哒';
 function crossDomainRequest() {
  document.getElementById('content').innerHTML = "<font color='red'>loading...</font>";
  // 延迟执行
  setTimeout(function () {
   if (xhr) {
    xhr.open('GEt', url, true);
    xhr.onreadystatechange = handle_response;
    xhr.send(null);
   } else {
    document.getElementById('content').innerText = "不能创建XMLHttpRequest对象";
   }
  }, 3000);
 }

 function handle_response() {
  var container = document.getElementById('content');
  if (xhr.readyState == 4) {
   if (xhr.status == 200 || xhr.status == 304) {
    container.innerHTML = xhr.responseText;
   } else {
    container.innerText = '不能跨域请求';
   }
  }
 }
</script>

</body>
</html>

然后对应的test1.php应该帮助我们实现数据请求这个过程,把“小红的联系方式”要到手,并返回给“小明”。

<?php

$url = 'http://api.qingyunke.com/api.php?key=free&appid=0&msg=hello world.';
$result = file_get_contents($url);
echo $result;

?>

下面看下代码执行的结果。

代理模式下的跨域实现

jsonp方式

JSONP(JSON with Padding) 灵感其实源于在HTML页面中script标签内容的加载,对于script的src属性对应的内容,浏览器总是会对其进行加载。于是:

克服该限制更理想方法是在 Web 页面中插入动态脚本元素,该页面源指向其他域中的服务 URL 并且在自身脚本中获取数据。脚本加载时它开始执行。该方法是可行的,因为同源策略不阻止动态脚本插入,并且将脚本看作是从提供 Web 页面的域上加载的。但如果该脚本尝试从另一个域上加载文档,就不会成功。

实现的思路就是:

在服务器端组装出客户端预置好的json数据,通过回调的方式传回给客户端。

原生实现

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>ajax 测试</title>
 <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js" type="text/javascript"></script>
</head>
<body>
<input type="text" name="talk" id="talk">
<input type="button" value="Test" id="btn">
<div id="content"></div>
<script type="text/javascript">

function jsonpcallback(result) {
 for(var i in result) {
  alert(i ":" result[i]);
 }
 }
 var JSONP = document.createElement("script");
 JSONP.type='text/javascript';
 JSONP.src='http://localhost/learn/ajax/test1.php?callback=jsonpcallback';
 document.getElementsByTagName('head')[0].appendChild(JSONP);


</script>

</body>
</html>

服务器端test1.php内容如下:

<?php

$arr = [1,2,3,4,5,6];
$result = json_encode($arr);
echo "jsonpcallback(".$result.")";

?>

需要注意的是最后组装的返回值内容。

来看下最终的代码执行效果。

JSONP原生跨域实现

JQuery方式实现

采用原生的JavaScript需要处理的事情还是蛮多的,下面为了简化操作,决定采用jQuery来代替一下。

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>ajax 测试</title>
 <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.8.0.js" type="text/javascript"></script>
</head>
<body>
<input type="text" name="talk" id="talk">
<input type="button" value="Test" id="btn">
<div id="content"></div>

<script type="text/javascript">

 function later_action(msg) {
  var element = $("<div><font color='green'>" msg "</font><br /></div>");
  $("#content").append(element);
 }

 $("#btn").click(function(){
  // alert($("#talk").val());
  $.ajax({
  url: 'http://localhost/learn/ajax/test1.php',
  method: 'post',
  dataType: 'jsonp',
  data: {"talk": $("#talk").val()},
  jsonp: 'callback',
  success: function(callback){
   console.log(callback.content);
   later_action(callback.content);
  },
  error: function(err){
   console.log(JSON.stringify(err));

  },
 });
 });
</script>

</body>
</html>

相应的,test1.php为了配合客户端聊天的需求,也稍微做了点改变。

<?php
$requestparam = isset($_GET['callback'])?$_GET['callback']:'callback';

// 青云志聊天机器人接口: http://api.qingyunke.com/api.php?key=free&appid=0&msg=hello
// 接收来自客户端的请求内容
$talk = $_REQUEST['talk'];
$result = file_get_contents("http://api.qingyunke.com/api.php?key=free&appid=0&msg=$talk");

// 拼接一些字符串
echo $requestparam . "($result)";

?>

最后来查看一下跨域的效果吧。

JSONP 跨域实现聊天应用

总结

至此,关于简单的ajax跨域问题,就算是解决的差不多了。对我个人而言,对于这三种方式有一点点自己的看法。

  1. 服务器设置Access-Control-Allow-Origin的方式适合信用度高的小型应用或者个人应用。
  2. 代理模式则比较适合大型应用的处理。但是需要一个统一的规范,这样管理和维护起来都会比较方便。
  3. JSONP方式感觉还是比较鸡肋的(有可能是我经验还不足,没认识到这个方式的优点吧(⊙﹏⊙)b)。自己玩玩知道有这么个东西好了。维护起来实在是优点麻烦。

参考链接:

Ajax跨域请求: https://www.jb51.net/article/72703.htm

服务器端跨域设置: https://www.jb51.net/article/104442.htm

Ajax高级笔记: https://www.jb51.net/article/116878.htm

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

详解ajax跨域问题解决方案的更多相关文章

  1. 应用程序关闭时的iOS任务

    我正在构建一个应用程序,通过ajax将文件上传到服务器.问题是用户很可能有时不会有互联网连接,并且客户希望在用户重新连接时安排ajax调用.这可能是用户在离线时安排文件上传并关闭应用程序.应用程序关闭时可以进行ajax调用吗?

  2. android – Phonegap本地构建 – jquery ajax错误:readystate 0 responsetext status 0 statustext error

    解决方法您是否在索引文件中包含了内容安全元标记?

  3. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  4. Ajax简单的异步交互及Ajax原生编写

    一提到异步交互大家就会说ajax,仿佛ajax这个技术已经成为了异步交互的代名词.那下面将研究ajax的核心对象

  5. 简单易懂的JSONP和CORS跨域方案详解

    这篇文章主要为大家介绍了简单易懂的JSONP和CORS跨域方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  6. Ajax跨域问题的解决办法汇总(推荐)

    本文给大家分享多种方法解决Ajax跨域问题,非常不错具有参考借鉴价值,感兴趣的朋友一起学习吧

  7. ajax编写简单的登录页面

    这篇文章主要为大家详细介绍了ajax编写简单登录页面的具体代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. ajax从JSP传递对象数组到后台的方法

    今天小编就为大家分享一篇ajax从JSP传递对象数组到后台的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

  9. 解决ajax返回验证的时候总是弹出error错误的方法

    这篇文章主要介绍了解决ajax返回验证的时候总是弹出error错误的方法,感兴趣的小伙伴们可以参考一下

  10. 使用AJAX完成用户名是否存在异步校验

    这篇文章主要介绍了使用AJAX完成用户名是否存在异步校验的相关资料,需要的朋友可以参考下

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部