因为面向互联网的性质,我们公司的大部分系统都采用多子域的方式进行开发和部署,以达到松耦合和分布式的目的,因此子系统间的交互不可避免。虽然通过后台的rpc框架解决了大部分的交互问题,但有些情况下,前端直接发起的各子系统之间交互仍然不可避免。由于浏览器天然的安全性本质,早期通常是不允许直接调用不同域名下的请求。如果直接调用不同域下的请求,会报“No 'Access-Control-Allow-Origin' header is present on the requested resource”错误。

所以在HTML 5以前,都是变相的方式绕过,主要有如下几种方式:

JSONP

我们发现,Web页面上调用js文件时不受是否跨域的影响,凡是拥有"src"这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>。那就是说如果要跨域访问数据,就服务端只能把数据放在js格式的文件里。恰巧我们知道JSON可以简洁的描述复杂数据,而且JSON还被js原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据。然后客户端就可以通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的js格式文件。客户端在对JSON文件调用成功之后,也就获得了自己所需的数据。这就形成了JSONP的基本概念。允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

在angularjs中,通常是如下:

$http.jsonp(url + "?callback=JSON_CALLBACK") .success(function(data) {
 将data赋值给$scope的某些属性
});

但JSONP只支持get,这样就限制了传递的数据量。所以就有了HTML 5里面的CORS。

CORS

Cross-Origin Resource Sharing (CORS) 是W3c工作草案,它定义了在跨域访问资源时浏览器和服务器之间如何通信。CORS背后的基本思想是使用自定义的HTTP头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。CORS规范简单地扩展了标准的XHR对象,以允许JavaScript发送跨域的XHR请求。它会通过
预检查(preflight)来确认是否有权限向目标服务器发送请求。

CORS与JSONP相比,更为先进、方便和可靠。

1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。如下:


对一个简单的请求,没有自定义头部,要么使用GET,要么使用POST,它的主体是text/plain,请求用一个名叫Orgin的额外的头部发送。Origin头部包含请求页面的头部(协议,域名,端口),这样服务器可以很容易的决定它是否应该提供响应。
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。
Header set Access-Control-Allow-Origin *

对于springboot(没有前置nginx时),可以如下配置:

    private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用
corsConfiguration.addAllowedHeader("*"); // 2允许任何头
corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等)
return corsConfiguration;
} @Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4
return new CorsFilter(source);
}

为了防止XSS攻击我们的服务器, 我们可以限制域,比如在nginx中可以如下设置:

http {
......
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
......
}

具体参见https://michielkalkman.com/snippets/nginx-cors-open-configuration.html

上述都配置了,nginx报“

2019/01/24 16:14:20 [error] 18728#24984: *67 access forbidden by rule, client: 127.0.0.1, server: localhost, request: "OPTIONS /tabase/taprocess/diagram/loadAllNodeState.json?instanceId=20190121_aop_1 HTTP/1.1", host: "localhost"”,客户端报:

Failed to load http://localhost/tabase/taprocess/diagram/loadAllNodeState.json?instanceId=20190121_aop_1: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8086' is therefore not allowed access.

此时请求在nginx就出错了,因为nginx在windows,所以不是权限的问题。

解决方法:

增加如下:

         limit_except GET POST OPTIONS {
deny all;
}
或者去掉limit_except

Failed to load http://localhost/tabase/taprocess/diagram/loadAllNodeState.json?instanceId=20190121_aop_1: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8086', but only one is allowed. Origin 'http://localhost:8086' is therefore not allowed access.

nginx和后台同时包含了跨域处理,去掉一个即可。

Failed to load http://localhost/tabase/taprocess/diagram/loadAllNodeState.json?instanceId=20190121_aop_1: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://localhost:8086' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

因为使用了下列选项:

xhrFields: {
withCredentials: true
},

不能使用*。

jquery.min.js:5 Failed to load http://localhost/tabase/taprocess/diagram/loadAllNodeState.json?instanceId=20190121_aop_1: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://localhost:8086' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

增加

add_header Access-Control-Allow-Credentials true;

Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

在Access-Control-Allow-Headers增加所有的头类型,例如:

add_header Access-Control-Allow-Headers Origin,X-Requested-With,Content-Type,Accept;

所以使用nginx的完整配置如下(配置nginx,就去掉tomcat的cors):

        location ^~ /tabase/ {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Headers Origin,X-Requested-With,Content-Type,Accept;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Credentials true;
#root html;
#index testssl.html index.html index.htm;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://10.20.39.223:38080;
}
# 注意,不要limit_except选项

在angularjs中,我们可以如下调用cors请求:

myApp.config(function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
});
myApp.controller("JsonController",function($scope,$http) {
$scope.getAjax = function(url) {
$http.get(url).success(function (response) {
$scope.students = response;
});
};
});

ajax跨子域请求的两种现代方法的更多相关文章

  1. nginx/ajax跨子域请求的两种现代方法以及403解决

    因为面向互联网的性质,我们公司的大部分系统都采用多子域的方式进行开发和部署,以达到松耦合和分布式的目的,因此子系统间的交互不可避免.虽然通过后台的rpc框架解决了大部分的交互问题,但有些情况下,前端直 ...

  2. Ajax跨域问题的两种解决方法

    浏览器不允许Ajax跨站请求,所以存在Ajax跨域问题,目前主要有两种办法解决. 1.在请求页面上使用Access-Control-Allow-Origin标头. 使用如下标头可以接受全部网站请求: ...

  3. ASP.NET MVC 实现AJAX跨域请求的两种方法

    通常发送AJAX请求都是在本域内完成的,也就是向本域内的某个URL发送请求,完成部分页面的刷新.但有的时候需要向其它域发送AJAX请求,完成数据的加载,例如Google. 在ASP.NET MVC 框 ...

  4. PHP允许AJAX跨域请求的两种方法

    * 一. 服务端设置 header 头允许AJAX跨域 ** 代码如下: // 允许 ityangs.net 发起的跨域请求 header("Access-Control-Allow-Ori ...

  5. vue 使用axios 出现跨域请求的两种解决方法

    最近在使用vue axios发送请求,结果出现跨域问题,网上查了好多,发现有好几种结局方案. 1:服务器端设置跨域 header(“Access-Control-Allow-Origin:*”); h ...

  6. AJAX跨域请求json数据的实现方法

    这篇文章介绍了AJAX跨域请求json数据的实现方法,有需要的朋友可以参考一下 我们都知道,AJAX的一大限制是不允许跨域请求. 不过通过使用JSONP来实现.JSONP是一种通过脚本标记注入的方式, ...

  7. GET和POST是HTTP请求的两种基本方法,区别是什么!?

    GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己 ...

  8. Javascript跨域请求的几种解决方法

    什么情况下才会出现跨域? 假设域名是:http://www.example.com.cn/ 如果所请求的域名跟这个域名不致,这种情况就是跨域,由于跨域存在漏洞,所以一般来说正常的跨域请求方式是请求不到 ...

  9. ASP.NET MVC 实现AJAX跨域请求方法《1》

    ASP.NET MVC 实现AJAX跨域请求的两种方法 通常发送AJAX请求都是在本域内完成的,也就是向本域内的某个URL发送请求,完成部分页面的刷新.但有的时候需要向其它域发送AJAX请求,完成数据 ...

随机推荐

  1. WPF自定义控件

    一.ImageButton 1.继承ImageButtonButton,添加依赖属性 using System; using System.Windows; using System.Windows. ...

  2. 关于织梦系统不支持php中GD库的问题

    大多数人在显成的PHP的CMS时,如织梦CMS,安装的时候不支持GD库,就导致整个网站的验证码不显示,以下是个人对此类问题的解决办法: 1.首先找到wamp的安装目录,找到PHP的文件夹,打开php. ...

  3. [转]使用ant让Android自动打包的build.xml,自动生成签名的apk文件(支持android4.0以上的版本)

    在android4.0以后的sdk里那个脚本就失效了,主要是因为 apkbuilder这个程序不见了: 人家sdk升级,我们的脚本也要跟上趟,修改一下喽. 上网一查,大家的文章还停留在我去年的脚本程度 ...

  4. DSP中CMD文件

    DSP中CMD文件 (2012-12-26 20:54:17) 转载▼ 标签: 杂谈 分类: DSP FPGA DSP的存储器的地址范围,CMD是主要是根据那个来编的.CMD 它是用来分配rom和ra ...

  5. 另类angularjs应用

    回顾 上一篇文章主要讲解了创建兼容任意浏览器(主要是ie的一些奇葩问题)的angularjs web应用,但是项目开发中其实更重要的还是在功能的模块化.代码自动压缩上面,这样项目在后期维护或者功能的重 ...

  6. hdu 2014鞍山赛区 5073 Galaxy

    题意:就是给你 n 个数,代表n个星球的位置,每一个星球的重量都为 1 ! 开始的时候每一个星球都绕着质心转动,那么质心的位置就是所有的星球的位置之和 / 星球的个数 现在让你移动 k 个星球到任意位 ...

  7. 2014 网选 5011 Game(Nim游戏,数学题)

    /* 题意:Nim游戏! 思路:通过异或,判断将n个数表示成二进制的形式之后,是否对应位的数字1 的个数是偶数! */ #include<iostream> using namespace ...

  8. Nopcommerce主要的技术

    Nopcommerce主要用到的技术及特点: 1.Entity Framework 2.ASP.NET mvc 3.IoC容器+依赖注入(Autofac) 4.使用EF中的EntityTypeConf ...

  9. bootstrap插件学习-bootstrap.tab.js

    先看bootstrap-tab.js的结构 var Tab = function ( element ) {} //构造器 Tab.prototype ={} //构造器的原型 $.fn.tab = ...

  10. 数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现

    概要 线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列.本章先介绍线性表的几个基本组成部分:数组.单向链表.双向链表:随后给出双向链表的C.C++和Java三种语言的实现. ...