跨域访问知多少

2021-01-14 15:40:22 浏览数 (1)

什么是跨域

因为浏览器的同源策略导致了跨域,就是浏览器在搞事情。

什么同源策略

浏览器的同源策略,要同源说起。顾名思义,同源就是源头相同,即两个页面的协议、端口和域名都相同,任何一个不满足,都会导致跨域。

下表给出了相对http://www.baibai.com/say/one.html同源检测的示例:

URL

结果

原因

http://www.baibai.com/say/other.html

成功

同一域名,同一文件夹

http://www.baibai.com/say/hi/another.html

成功

同一域名,不同文件夹

https://www.baibai.com/say/oneByOne.html

失败

不同协议 ( https和http )

http://www.baibai.com:81/say/two.html

失败

不同域名 ( news和www )

http://news.baibai.com/say/three.html

失败

不同域名 ( news和www )

跨域如何解决

场景1:基于前端jquery的跨域

如果是一般的ajax请求:

代码语言:javascript复制
  $.ajax({

     url:'http://news.baibai.com/say/test/testjsonp',

      type :'get',

      dataType :'text',

     success:function(data){

         alert(data);

      },

      error:function(data){

          alert(“error”);

     }       

 });

那么在浏览器中会报错。

如果改用jsonp形式的ajax请求,并且通过get请求的方式传入参数,注意:跨域请求是只能是get请求不能使用post请求。

代码语言:javascript复制
 <!DOCTYPEhtml>

  <html>

    <head>

    <metacharset="UTF-8">

    <title>Inserttitle here</title>

    <scripttype="text/javascript"src="./js/jquery.js"></script>

    <scripttype="text/javascript">

     $(document).ready(function(){

          var newId = 1928273643';

          $.ajax({

             type :'get',

             url:'http://news.baibai.com/say/test/testjsonp',

             data : {

                 newId: newId,

             },

             cache:false,

             jsonp:"callback",

            jsonpCallback:"success",

             dataType :'jsonp',

            success:function(data){

                alert(data);

             },

            error:function(data){

                alert('error');

             }       

         });

     });

    </script>

    </head>

    <body>

         <input id=newId'value='546' name=’new'>

         <divid='testdiv'></div>

     </body>

 </html>

jsonp 传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)。

jsonpCallback自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名。

场景2:基于后端Java的跨域

自从HTML5出现之后,极大地方便了日常的开发。其实浏览器并没有拦截请求,而是拦截了服务器端返回的响应。所以如果要支持跨域访问,需要浏览器和后台服务器程序同时支持,如果这两个条件不能同时满足,则还是不能支持跨域访问。

响应头有以下几种:

  • Access-Control-Allow-Origin:允许跨域访问的域,可以是一个域的列表,也可以是通配符”*”;
  • Access-Control-Allow-Methods:允许使用的请求方法,以逗号隔开;
  • Access-Control-Allow-Headers:允许自定义的头部,以逗号隔开,大小写不敏感;
  • Access-Control-Expose-Headers:允许脚本访问的返回头,请求成功后,脚本可以在XMLHttpRequest中访问这些头的信息。
  • Access-Control-Allow-Credentials:是否允许请求带有验证信息,XMLHttpRequest请求的withCredentials标志设置为true时,认证通过,浏览器才将数据给脚本程序。

请求头有以下几种:

  • Origin:表明来源域,要与响应头中的Access-Control-Allow-Origin相匹配才能进行跨域访问;
  • Access-Control-Request-Method:将要进行跨域访问的请求方法,要与响应头中的Access-Control-Allow-Methods相匹配才能进行跨域访问;
  • Access-Control-Request-Headers:自定义的头部,所有用setRequestHeader方法设置的头部都将会以逗号隔开的形式包含在这个头中,要与响应头中的Access-Control-Allow-Headers相匹配才能进行跨域访问。 如果想要能够跨域进行访问,需要设置如下代码,即在返回头中添加一些字段:
代码语言:javascript复制
@Override

 public void doFilter(ServletRequest request, ServletResponse response) throws IOException,ServletException {

       HttpServletRequest req =(HttpServletRequest) request;

       HttpServletResponse rep =(HttpServletResponse) response;

       // 设置允许请求的域名,即白名单

       String allowDomains = {"http://news.baibai.com/say/three.html "};

       String originHeads = req.getHeader("Origin");

       if(allowOrigins.contains(originHeads)){

             rep.setHeader("Access-Control-Allow-Origin",originHeads);

       }

}

有时候,在跨域访问的时候会存在访问方式是出了post,get类型的,比如options类型,这种会在有的代码中拦截,无法访问,需要在返回头中加如下字段:

代码语言:javascript复制
response.setHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE");

有时候,访问的请求头首部出现其他类型, 那么Access-Control-Allow-Headers 响应首部预检请求,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。如:

代码语言:javascript复制
response.setHeader("Access-Control-Allow-Headers","x-requested-with,Origin,Accept");

有时候,会出现前端接口对接的时候,后台一直获取不到值。最后发现request里有值,session也有值,但是session的id却不一致。这就是因为跨域引起的,需要在fitter里加上以下代码:

代码语言:javascript复制
response.setHeader("Access-Control-Allow-Credentials","true");

response.setHeader("XDomainRequestAllowed","1");

注意,当在后端Java代码中加入以上代码时,也需要在前端ajax中加入代码:

代码语言:javascript复制
var xhr = new XMLHttpRequest();

xhr.withCredentials = true;

再次注意: 服务器端Access-Control-Allow-Credentials = true时,参数Access-Control-Allow-Origin的值不能为 '*'

0 人点赞