因为面向互联网的性质,我们公司的大部分系统都采用多子域的方式进行开发和部署,以达到松耦合和分布式的目的,因此子系统间的交互不可避免。虽然通过后台的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. 搬家至个人独立博客virson.cn

    最近正在将博客园的文章搬到自己的独立博客,以后基本上不会在博客园更新文章了,欢迎光临我的新博客:www.virson.cn,博客内容持续更新中……

  2. VC中使用ATL库实现正则表达式匹配(ADODB::Error)

    1. 确保项目属性中ATL使用处于打开状态. 如VS中项目属性常规—ATL使用—静态链接到ATL 2. 在使用时加上头文件 #include "atlrx.h" 3. 使用示例代码 ...

  3. Android开发之ProgressDialog在独立Thread线程中更新进度

    简单的需求:在一个工作Thread中更新进度对话框ProgressDialog 遇到的问题: 1,创建需要Context,这个需要传进来 2,Thread中不能创建ProgressDialog,否则需 ...

  4. redis的主从复制部署和使用

    reids一种key-value的缓存数据库目前非常流行的被使用在很多场景,比如在数据库读写遇到瓶颈时缓存且读写分离会大大提升这块的性能,下面我就说说redis的主从复制 首先需要启动多个redis实 ...

  5. 节日EDM系列:圣诞节如何进行EDM数据营销

    消费关系升级,消费者看中的早已不是产品本身,场景消费以及消费带来的价值感体验已成为影响消费的重要因素.圣诞将至,如何才能将圣诞节EDM数据营销的效果发挥到极致? ①  节日元素创意融合,高辨识度加深品 ...

  6. python高效解析日志入库

    python脚本解析日志文件入库一般有三个重要的步骤:读文件.解析文件.入库.在这三个方面下功夫,可确保我们获得最优的性能(这里不讨论并发) 1 读文件:一次读一行,磁盘IO太多,效率低下:一次性读如 ...

  7. 突破GFW,使用node.js

    原文链接:https://cnodejs.org/topic/4f9904f9407edba21468f31e 这个也是网上搜的,亲自试过,非常好用! 镜像使用方法(三种办法任意一种都能解决问题,建议 ...

  8. CSS 块状元素和内联元素

    在用CSS布局页面的时候,我们会将HTML标签分成两种,块状元素和内联元素(我们平常用到的div和p就是块状元素,链接标签a就是内联元素) 块状元素一般是其他元素的容器,可容纳内联元素和其他块状元素, ...

  9. swift实现冒泡排序

    刚刚坐着没事干,就用swift语言写了写冒泡排序,还望高手指点.拍砖!哈哈! 废话不多说,上代码! import Cocoa var array = [,,,,,,,,,,,,,,,,,] print ...

  10. web.config中httpRunTime的属性

    配置httpRuntime也可以让FileUpload上传更大的文件,不过设置太大了会因用户将大量文件传递到该服务器而导致的拒绝服务攻击(属性有说明) <httpRuntime> < ...