Ajax的跨域问题

138 阅读3分钟

一、什么是ajax跨域问题

ajax跨域问题发生的根源,在于浏览器的同源策略。

什么是同源?

这里的“源”,又称为“域”,它是协议名、主机名、端口号的统称。而同源,则是指两个地址的“源”相同,也就是协议名、主机名、端口号完全相同

也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。

跨域问题是针对JS和ajax的,html本身没有跨域问题。

查看浏览器开发者工具Console报错:

Failed to load a.a.com:8080/A/FromServl…: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'b.b.com:8080' is therefore not allowed access.

http://baidu.com/http://www.baidu.com/×(域名不同)

http://www.baidu.com/https://www.baidu.com/×(协议不同)

http://localshot/http://127.0.0.1/×(域名不同)

http://localshot/http://localshot:8088/×(端口不同)

http://localshot/http://localshot/

注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。

二、如何解决跨域

第一种方式:jsonp跨域


所谓jsonp就是在服务器端会给你输出一个字符串函数,你通过在本地定义一个同样名字的函数去执行就可以了。如果你不了解后端,也没有关系,你可以直接复制下面的例子来输出接口数据。

原生javascript跨域的例子:

 <style type="text/css">
   #con { width: 300px;height: 50px;}
   #box div{ width: 300px; height: 30px; border: 1px solid red; }
</style>

<input type="text" id="con" value="" />
   <div id="box"></div>
   <script type="text/javascript">
       var con=document.getElementById("con");
       var box=document.getElementById("box");
       var script1=null;
       function callback(str){
           var json=str.s;
           for (var i=0; i<str.s.length;i++){
              box.innerHTML+="<div>"+str.s[i]+"</div>"
           }
       }

       con.onkeyup=function(){
           box.innerHTML="";
              if(script1){
                 document.body.removeChild(script1);
              }
              script1=document.createElement("script");
              script1.src="[http://suggestion.baidu.com/su?cb=callback&wd="+con.value;](http://suggestion.baidu.com/su?cb=callback&wd=)
              document.body.appendChild(script1);
       };
</script>

jquery jsonp跨域的例子:

 $.ajax({
  async:false,         // 是否是同步请求
  url:"[http://ad.bjnews.com.cn/service/getad?pid=1](http://ad.bjnews.com.cn/service/getad?pid=1)",// 地址
  type:"GET",          // 请求方式
  dataType:"jsonp",    // 请求的数据类型
  jsonp: 'callback',   // callback的函数名 
  jsonpCallback:"callback_adservice",
  data: {},            // 你要发送的数据 内容是名值对形式的
  success:function(data){
    alert(data)
  },
  //诊断错误类型
  error:function(jqXHR,textStatus,errorThrown){
    console.log(jqXHR);
    console.log(textStatus);
    console.log(errorThrown);
  }
})

注意:jsonp 只支持get请求不支持post请求

第二种方式:跨域资源共享—CORS


跨源资源共享(CORS)是通过客户端+服务端协作声明的方式来确保请求安全的。服务端会在HTTP请求头中增加一系列HTTP请求参数(例如Access-Control-Allow-Origin等),来限制哪些域的请求和哪些请求类型可以接受,而客户端在发起请求时必须声明自己的源(Orgin),否则服务器将不予处理,如果客户端不作声明,请求甚至会被浏览器直接拦截都到不了服务端。服务端收到HTTP请求后会进行域的比较,只有同域的请求才会处理。

cors前端代码示例:

 function getHello() {
    var xhr = new XMLHttpRequest();
    xhr.open("post", "[http://b.example.com/Test.ashx](http://b.example.com/Test.ashx)", true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    // 声明请求源
    xhr.setRequestHeader("Origin", "[http://a.example.com");](http://a.example.com/)
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            var responseText = xhr.responseText;
            console.info(responseText);
        }
    }
    xhr.send();
}

第三种方式:响应头添加Header允许访问

跨域资源共享(CORS)Cross-Origin Resource Sharing

这个跨域访问的解决方案的安全基础是基于"JavaScript无法控制该HTTP头"

它需要通过目标域返回的HTTP头来授权是否允许跨域访问。

response.addHeader(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
response.addHeader(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式

第四种方式:Webpack使用代理proxy解决跨域问题

wepack默认http协议,如果要代理https协议,需要增加:

secure:false

proxyTable:
//当你请求是以v2开头的接口,则我帮你代理访问到https://api.douban.com
'/v2/*':{
        target:'https:/api.douban.com',         //你接口的域名
        secure:false,          //如果是https接口,需要配置这个参数
        changeOrigin:true,     //如果接口跨域,需要进行这个参数配置
        }
}