【Ajax】跨域的产生及如何解决跨域问题

什么是跨域? 为什么会出现跨域

浏览器为了保护用户, 保证用户安全,使用同源策略 来针对请求做出响应。
同源:
协议相同:protocol(ftp file http https 等协议)不同得协议被服务器认为不同源
域名相同:domain网站得域名必须一致。
端口相同:port默认80端口,但是不同端口也被认为跨域
以上任何不相同都被认为是跨域。

简单的说:
1 · 使用xmlHttpRequest,即我们通常说的ajax请求
2 · 浏览器做了这个事
3 · 访问的域名不同,即访问的html页面是a域名下的,但内部js发送的ajax请求的目标地址却是b域名

以上三个条件缺一不可,尤其是第三个条件,许多做移动端的同学可能都没有听过,因为移动端可以用各种http请求狂发不同的域名,但是浏览器不允许我们这么做

JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。跨域问题是针对JS和ajax的,html本身没有跨域问题,比如a标签、script标签、甚至form标签(可以直接跨域发送数据并接收数据)等。这是为了保证用户得安全。

说到底,跨域的原因是 前后端分离 ,跨域的目的是 安全


如何解决跨域问题(服务器代理, CORS,JSONP)

解决跨域问题的根本就是要打破上述的三个限制中的任何一个,我们可以逐个击破:

JSONP方式
jsonp是打破第一重限制,(因为)用了XMLHttpRequest就跨域,那不用这种方式了,我们来看一段jquery的jsonp格式的ajax请求:

$.ajax({
   type : "GET",
   url : "http://api.map.baidu.com/geocoder/v2/",
   data:"address=河南",
   dataType:"jsonp",
   jsonp:"callback",
   jsonpCallback:"showLocation",
   success : function(data){
	   alert("成功");
   },
   error : function(data){
   	   alert("失败");
   }
});

看似用了ajax请求,其实内部完全不是那么回事,多了jsonp和jsonpCallback选项,它内部将代码翻译并把页面上的dom操作成这样:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <script type='text/javascript'>
      // 后端返回直接执行的方法,相当于执行这个方法,由于后端把返回的数据放在方法的参数里,所以这里能拿到res。
      window.showLocation = function (res) {
        console.log(res)
        //执行ajax回调
      }
    </script>
    <script src='http://api.map.baidu.com/geocoder/v2/?address=河南&callback=showLocation' type='text/javascript'></script>
  </body>
</html>

这个时候,html页面的script src标签回去访问api.map.baidu.com的服务端,由于script,img这种标签浏览器是不受xmlhttprequest限制的,可以随意访问,这个时候对应的后端代码取得address参数,最后根据双方约定好的callback参数,返回一个被包装后的json

咦,上面我们为什么使用script标签?

script标签src允许跨域,我们利用script标签得src来访问资源,然后使用callback来承接返回得数据,并处理。

let input = document.queryselector("input")
input.oninput = function(){
    let script = document.createElement("script")
 	let url = `https://s.search.bilibili.com/main/suggest?jsoncallback=mycallback&term=${input.value}`
    script.src = url
    document.body.appendChild(script)
    script.onload = () => document.body.removeChild(script)
}
function mycallback(data){
    console.log(data)
}

其中url是我们需要请求得src,在src中拼接了一个完整得get请求,包括请求得参数请求时发送的数据,以及回调接口。
将script添加到页面中的时候,script的代码会立即解析执行,执行完成之后删除(若是原生封装的ajax,记得手动删除removeChild)。其中mycallback是本地的函数,这个函数接受参数用于使用参数。

CORS 后台允许跨域
在后台添加允许跨域:“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源(协议 + 域名 + 端口)服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。这里以node的koa框架为例:

//先npm并引入:const cors=require('koa2-cors')
app.use(cors({
	origin:['能够跨域ajax的url'],
	credentials:true
}))

第三方(也就是代理服务器)

文章https://m.imooc.com/article/288397中是这样说的:打破不同源的限制,我只要让它同源就可以了,比如要我的静态页面是 http://a.com/index.html 动态ajax请求访问的是http://b.com/api/***
我只需要将对应的服务部署在不同的机器上,然后使用一个公共的c.com的域名作为nginx反向代理的入口域名,在将静态服务和动态服务分别挂在后面的被代理局域网服务器内,修改配置


下面我们来详细看下nginx反向代理 的实战操作:

server
{
    listen 3002;
    server_name localhost;
    location /ok {
        proxy_pass http://localhost:3000;

        #   指定允许跨域的方法,*代表所有
        add_header Access-Control-Allow-Methods *;

        #   预检命令的缓存,如果不缓存每次会发送两次请求
        add_header Access-Control-Max-Age 3600;
        #   带cookie请求需要加上这个字段,并设置为true
        add_header Access-Control-Allow-Credentials true;

        #   表示允许这个域跨域调用(客户端发送请求的域名和端口) 
        #   $http_origin动态获取请求客户端请求的域   不用*的原因是带cookie的请求不支持*号
        add_header Access-Control-Allow-Origin $http_origin;

        #   表示请求头的字段 动态获取
        add_header Access-Control-Allow-Headers 
        $http_access_control_request_headers;

        #   OPTIONS预检命令,预检命令通过时才发送请求
        #   检查请求的类型是不是预检命令
        if ($request_method = OPTIONS){
            return 200;
        }
    }
}

相关文章推荐:
前端常用的几种跨域方式实践

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恪愚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值