ajax请求总是不成功?浏览器的同源策略和跨域问题详解

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
简介: XMLHttpRequest cannot load http://oldwang.com/isdad. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://xiao

场景

码农小明要做一个展示业务数据的大屏给老板看,里面包含了来自自己网站的数据和来自隔壁老王的数据。
那么自己网站的数据提供了 http://xiaoming.com/whoami 这样的数据接口
隔壁老王提供了 http://oldwang.com/isdad 这样的数据接口
单独点开都是没有问题的。但是一使用 js 的 ajax 请求就无法收到来自 oldwang.com 的数据了。
点开浏览器控制台一看,红字标出(Chrome):

XMLHttpRequest cannot load http://oldwang.com/isdad. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://xiaoming.com/' is therefore not allowed access.

这就是遇到了跨域问题

为什么会有这样的问题?

想象一下如果隔壁老王根本不认识你,他的网站自己有各种用户接口、订单接口、文章接口,那么谁都可以把这些接口返回的数据直接放在自己的网站上了,还是实时的。

所以浏览器制定了一个 同源策略 ,限制了从一个源(origin)中的脚本获取来自其他源(origin)中的资源。

什么是同源

如果两个页面拥有相同的协议(protocol: http),端口(port: 80),和主机(host: xiaoming.com),那么这两个页面就属于同一个源(origin)。

解决方案

这里就不讲多年前的iframe、flash等方式了,只讲几个最常用到的方案

A.x.com 和 B.x.com 间的跨域

子域名不同也是会受到跨域限制的。这种问题最简单,只需要将页面声明为更高级的域就可以了。

<script>
  document.domain = "x.com";
</script>

最经典、高效、浏览器兼容最好的解决方案:JSONP

但是有一个致命的缺点:非常高的跨站脚本攻击风险,所以 DataV 是不支持这种方式的

看到JSONP这个名字很多人以为这是和JSON密切相关的一种用来跨域的黑科技,但实际上从跨域的视角看,跟JSON并没有一毛钱关系,他是利用了浏览器允许跨域加载 js 等资源来获取数据。

因为浏览器支持跨域加载 js 如 <script src="http://aliyun.com/....."></script> ,所以很简单,可以把数据包装成 js 就可以了。

这是数据,通过 script 加载到数据无法“执行”,更无法传给 ajax 的回调函数:

{
  "data": 123
}

这是js脚本,只要将 callback 与 ajax 的回调函数做关联,就可以讲数据传给回调函数:

callback({
  "data": 123
})

这可以看到四点:

一、需要 callback 与 ajax 回调函数绑定;
二、需要数据服务器 配合 的。
三、只支持GET请求
四、数据服务器可以随意插入危险的脚本

前端如果用 jquery,jquery已经完成了整个取值过程的封装,逻辑是:

  1. 随机生成不重复的 callback 函数名,并与 ajax 回调函数 绑定。
  2. 将 callback 函数名放入 URL 的 query string 中,如 http://oldwang.com/api?callback= jQuery214015557975923291245_1460532274390
  3. 生成一个 <script> 标签,将上述 URL 作为 src
  4. 等待数据加载,并把数据传入 ajax 的回调函数

后端以 php 为例,逻辑是获取浏览器传来一个参数作为callback包装数据:

<?php
  echo $_GET['callback']."(". $data .")";
?>

大部分新浏览器都兼容的 CORS(Cross Origin Resource Sharing)

他的原理是隔壁老王主动告诉浏览器“别拦着小明,我们是亲戚……”
所以最简单的例子,就是在数据服务器返回的头信息中包含:

Access-Control-Allow-Origin: http://xiaming.com

然而这个头信息并不支持枚举,那如果隔壁老王的亲戚太多就只能通过程序来动态得生成这个头信息了,以PHP为例:

<?php 
if (is_my_bastard($_SERVER['HTTP_ORIGIN'])) {
 header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
}
?>

如果老王作为一个好人,来者不拒。那么可以直接使用 *

Access-Control-Allow-Origin: *

Cookies

CORS默认是不带 cookie 信息的,如果要带上 cookie 需要添加 withCredentials 参数,以 jquery 为例:

$.ajax({
    url: "http://laowang.com/isdad",
    xhrFields: {
      withCredentials: true
    }
  });

而服务器还需要加上允许 Credentials 的头信息以及不允许用通配符“*”,如下面的代码

<?php 
if (is_my_bastard($_SERVER['HTTP_ORIGIN'])) {
  header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); // 不允许用 *
  header("Access-Control-Allow-Credentials:true");
}
?>

这就是隔壁老王的故事

其他参数可以参阅:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
|
1月前
|
XML 前端开发 JavaScript
|
20天前
|
移动开发 JSON JavaScript
|
2月前
|
JSON JavaScript 前端开发
《进阶篇第6章:vue中的ajax》包括回顾发送ajax请求方式、vue-cli脚手架配置代理服务器、vue-resource
《进阶篇第6章:vue中的ajax》包括回顾发送ajax请求方式、vue-cli脚手架配置代理服务器、vue-resource
59 22
|
1月前
|
存储 安全 JavaScript
浏览器的同源策略
【10月更文挑战第31天】浏览器的同源策略是浏览器安全模型的重要组成部分,它通过限制不同源之间的资源交互,有效地保护了用户和网站的安全。开发者在进行Web开发时,需要充分理解和遵循同源策略,同时合理地运用各种跨域技术来满足业务需求,确保网站的安全性和功能性的平衡。
46 2
|
2月前
|
前端开发 JavaScript
回顾前端页面发送ajax请求方式
回顾前端页面发送ajax请求方式
38 18
|
2月前
|
前端开发 JavaScript Java
第6章:Vue中的ajax(包含:回顾发送ajax请求方式、vue-cli脚手架配置代理服务器)
第6章:Vue中的ajax(包含:回顾发送ajax请求方式、vue-cli脚手架配置代理服务器)
81 4
|
2月前
|
Web App开发 JSON 安全
Chrome浏览器的跨域问题
【10月更文挑战第6天】
|
2月前
|
前端开发 JavaScript 数据处理
JQuery 拦截请求 | Ajax 请求拦截
【10月更文挑战第4天】
110 1
|
3月前
|
JSON JavaScript 前端开发
Jquery常用操作汇总,dom操作,ajax请求
本文汇总了jQuery的一些常用操作,包括DOM元素的选择、添加、移除,表单操作,以及如何使用jQuery发送Ajax请求,涵盖了GET、POST请求和文件上传等常见场景。
|
3月前
|
JSON 前端开发 JavaScript
java中post请求调用下载文件接口浏览器未弹窗而是返回一堆json,为啥
客户端调接口需要返回另存为弹窗,下载文件,但是遇到的问题是接口调用成功且不报错,浏览器F12查看居然返回一堆json,而没有另存为弹窗; > 正确的效果应该是:接口调用成功且浏览器F12不返回任何json,而是弹窗另存为窗口,直接保存文件即可。
148 2