【前端】跨域 问题 原理 + 解决方案 上

版权声明:高性能MySQL是第3版,注意mysql版本;很多博客都参考或者直接转载自网络,如果不方便被转载,看到请与我联系 https://blog.csdn.net/ma15732625261/article/details/82258611

起源:

错误是由于CORS跨域验证机制设置不正确导致的,但是上面的这个错误我得解决呀,不好办吗,本文结合各大……(广告时间)能说明白当然是不可能了,还需要点开文中链接看一看、瞧一瞧,当然偶尽量在本文中写滴清楚

这个前言让他有点特别吧,先写一下出现的几种问题:

No 'Access-Control-Allow-Origin' header is present on the requested resource,并且The response had HTTP status code 404

原因:(解决:后端允许options请求)

  • 本次ajax请求是“非简单请求”,非简单请求?嘿嘿 见下文
  • 服务器端后台接口没有允许OPTIONS请求,导致无法找到对应接口地址
No 'Access-Control-Allow-Origin' header is present on the requested resource,并且The response had HTTP status code 405

原因:(后端关闭对应的安全配置)

  • 方法允许OPTIONS请求,但是一些配置文件中(如安全配置),阻止了OPTIONS请求
No 'Access-Control-Allow-Origin' header is present on the requested resource,并且status 200

原因:(后端增加对应的头部支持)

  • 服务器端后台允许OPTIONS请求,并且接口也允许OPTIONS请求,但是头部匹配时出现不匹配现象
heade contains multiple values '*,*'

原因:

  • 重复配置
  • 常见于.net后台(一般在web.config中配置了一次origin,然后代码中又手动添加了一次origin(比如代码手动设置了返回*)): 建议删除代码中手动添加的*,只用项目配置中的即可
  • 常见于.net后台(在IIS和项目的webconfig中同时设置Origin:*):建议删除IIS下的配置*,只用项目的配置

正文:

浏览器安全的基石是"同源政策"(same-origin policy

跨域:浏览器不能执行其他网站的脚本,由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制;

一、概述:

同源:

协议、域名、端口相同;

http://www.example.com/dir/page.html这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略)
  • http://www.example.com/dir2/other.html:同源
  • http://example.com/dir/other.html:不同源(域名不同)
  • http://v2.www.example.com/dir/other.html:不同源(域名不同)
  • http://www.example.com:81/dir/other.html:不同源(端口不同)

 

目的:

保证用户信息的安全,防止恶意的网站窃取数据,这个文章的有两个例子,助于理解,其实挺好理解的

 

限制范围:

如果非同源,共有三种行为受到限制:

(1) Cookie、LocalStorage 和 IndexDB 无法读取。

(2) DOM 无法获得。

(3) AJAX 请求不能发送。

跨域请求、ajax技术提高页面体验同时带来安全隐患,如CSRF(cross-site request forgery)

跨站请求伪造

通过伪装来自受信任用户的请求来利用受信息的网站(一起慢慢读)

防范策略

1、验证http referer字段

http头有referer字段,记录请求来源地:简单易行但值由浏览器提供,不安全

2、请求地址中添加token并验证

对于 GET 请求,token 将附在请求地址之后,这样 URL 就变成 http://url?csrftoken=tokenvalue。 而对于 POST 请求来说,要在 form 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>

但对每个请求加很麻烦易漏,难保证token本身安全;GET 请求不需要 CSRF Token(因为写操作不应该用 GET),POST 请求在执行写操作時依旧需要 CSRF Token

3、http头中自定义属性并验证

将token放到http头自定义属性中,通过xmlHttpRequest类一次性给all请求加上csrftoken头属性将token放入其中

xmlhttprequest常用于ajax对页面局部的异步刷新,不是all请求都适合发起,且得到的页面不能被浏览器记录

规避限制,解决跨域:

 

JSONP:借助一些没有跨域限制的标签 限GET

HTML标签里,一些标签比如script、img这样的获取资源的标签(all拥有”src”这个属性的标签)没有跨域限制的

 

用JSON来传数据,靠JSONP来跨域【

1、json是数据交换格式,纯文本、跨平台、轻量、可读、易编写解析,JavaScript支持,almost后端语言支持

        格式:{一组“不同类型的无序键值对集合”}[一组“相同类型的有序数据集合”] :映射符 ,分隔符  ""定义符(字符串必须用“”引起)

2、jsonp:一种非官方跨域数据交互协议;web客户端通过调用脚本的方式,来调用跨域服务器上动态生成的js格式文件(一般以JSON为后缀)

        用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了;

        不再直接把远程js文件写死,而是编码实现动态查询:callback标识:我想要一段调用XXX函数的js代码,请你返回给我,服务器安装需求生成响应

<script type="text/javascript">
    // 得到航班信息查询结果后的回调函数
    var flightHandler = function(data){
        alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
    };
    // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
//callback参数告诉服务器,我的本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用
    var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
    // 创建script标签,设置其属性
    var script = document.createElement('script');
    script.setAttribute('src', url);
    // 把script标签加入head,此时调用开始
    document.getElementsByTagName('head')[0].appendChild(script);
</script>

前端可以用ajax实现,后端大概是这个样子,取出callback包装一下返回值【这个博客里面也有例子】 

    response.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");
    //数据
    List<Student> studentList = getStudentList();
    JSONArray jsonArray = JSONArray.fromObject(studentList);
    String result = jsonArray.toString();
    //前端传过来的回调函数名称
    String callback = request.getParameter("theFunction");
    //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
    result = callback + "(" + result + ")";
    response.getWriter().write(result);

CORS:Cross-Origin Resource Sharing 【

支持所有类型的HTTP请求

看到这个是不是有些熟悉,@CrossOrigin有没有用过,需要客户端和服务器同时支持

      估计我这里是服务器不支持的原因,每个方法都加了注解,项目加了过滤器、拦截器都不行,诶~宝宝的小心脏

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)【

对于简单请求, 浏览器可以自行解决其中的跨域问题. 例如我们熟知的一个跨域通信的解决方式JSON-P就是利用GET发送一个简单请求来规避跨域的问题.HTML中的表单提交也不需要处理跨域问题.【】(其实form是不需要处理的,下面会说,而且实践通过咯)

任何不符合上述条件的请求都算作非简单请求, 浏览器在处理非简单的跨域请求时会与服务器进行额外的通信(称之为预检请求)

简单请求

浏览器直接发出CORS请求:头信息之中,增加一个Origin字段

       说明本次请求来自哪个源(协议 + 域名 + 端口)服务器根据这个值,决定是否同意这次请求

如果源不在许可范围内,服务器会返回正常的http响应但头信息中无Access-Control-Allow-Origin,抛错被XMLHttpRequestonerror回调函数捕获;在许可范围,返回响应多出几个头信息字段:

//请求时origin字段的值,*表示接受任意域名的请求
Access-Control-Allow-Origin: http://api.bob.com

//可选,Boolean值,是否容许发送cookie;true 服务器许可 可包含在请求中发给服务器、只能设为true,如果服务器不要浏览器发cookie,删除字段即可
Access-Control-Allow-Credentials: true

//可选,cors请求时,xmlhttprequest的getResponseHeader拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers,下面可返回“FooBar”字段的值
Access-Control-Expose-Headers: FooBar

Content-Type: text/html; charset=utf-8//泥萌猜

CORS请求默认不发送Cookie和HTTP认证信息,如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段,另一方面,开发者必须在AJAX请求中打开withCredentials属性

var xhr = new XMLHttpRequest();   xhr.withCredentials = true;

$.post({
   url: ‘1747937498.PHP’,
   data: {
      appId: appId
   },
   dataType: "json",
   timeout:300000,
   xhrFields:{withCredentials: true},
   success: function (result) {
      
   },
   error: function () {

   }
});

要发送Cookie,Access-Control-Allow-Origin就不能设为星号,指定明确的、与请求网页一致的域名

非简单请求

指种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

“预检"请求

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
//请求的方法是PUT
xhr.open('PUT', url, true);
//发送一个自定义头信息X-Custom-Header
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的

1、头信息里面,关键字段Origin同上

2、Access-Control-Request-Method:浏览器的CORS请求会用到哪些HTTP方法

3、Access-Control-Request-Headers:逗号分隔的字符串,CORS请求会额外发送的头信息字段

预检请求的回应:

请求中Access-Control-Allow-Origin: http://api.bob.com或*表示可以请求

如果否定,返回正常http回应,无cors相关头信息,浏览器触发错误 同上

1、Access-Control-Allow-Methods:服务器支持的所有跨域请求的方法,避免多次预检请求

2、Access-Control-Allow-Headers:请求包括则该字段必需,支持的all头信息字段

3、Access-Control-Allow-Credentials

4、Access-Control-Max-Age:本次预检请求有效期,s

参考:

什么是跨域?解决跨域的五种方法。 

阮一峰大佬 跨域资源共享 CORS 详解

撒网要见鱼 https://segmentfault.com/a/1190000012469713

 Hosee CORS与CSRF https://my.oschina.net/hosee/blog/903665

https://www.cnblogs.com/chiangchou/p/jsonp.html jQuery jsonp 跨域请求

http://www.ruanyifeng.com/blog/2016/04/cors.html 跨域资源共享 CORS 详解

https://kb.cnblogs.com/page/139725/ 说说JSON和JSONP,也许你会豁然开朗

https://segmentfault.com/a/1190000015597029 这个链接失效了,奇怪 点不开

https://www.imooc.com/article/19869?block_id=tuijian_wz 一篇文章可以解决跨域

猜你喜欢

转载自blog.csdn.net/ma15732625261/article/details/82258611