乐趣区

关于javascript:Ajax跨域请求

1、Ajax 申请限度

Ajax 只能向本人的服务器发送申请

比方当初有一个 A 网站,一个 B 网站,A 网站中的 HTML 文件只能向 A 网站服务器发送 Ajax 申请,B 网站中的 HTML 文件只能向 B 网站服务器发送 Ajax 申请,然而 A 网站时不能向 B 网站发送 Ajax 申请的,同理,B 网站不能向 A 网站发送 Ajax 申请的

A 网站先 B 网站发送 Ajax 申请,咱们称之为 跨域申请

如:在本地关上 AJax 文件先服务器申请内容

下面报错熟不相熟,这就是因为产生了跨域申请导致的谬误

2、什么是同源

浏览器为了平安问题,做出了同源策略的限度,即跨域申请默认是不被容许的

这里所说的同源是指:协定名、主机号、端口号 这三局部是一样。雷同域之间的申请是不受限制的,而不同域之间不能相互申请的,这就是Ajax 的同源策略

如果两个页面领有雷同的协定、域名和端口,那么两个页面就属于同一个源,其中只有有一个不同,就是不同源

同源策略是为了爱护用户信息的平安,避免歹意的网站窃取数据,最后的同源策略是指 A 网站在客户端设置Cookie,B 网站则不能拜访的

3、解决跨域申请

Ajax默认是不容许进行跨域申请的,然而咱们却时常进行非同源申请,摆在咱们背后的就是解决跨域申请

解决跨域申请有 4 种办法:

  1. JSONP 解决跨域申请
  2. CORS 跨域资源共享
  3. 代理服务器
  4. 基于 <iframe> 标签

次要理解前两种

3.1 JSONP 解决跨域申请

JSONP 不属于 Ajax 申请,然而它能够模仿 Ajax 申请

有没有想过,咱们平时在 HTML 页面中的 <img><link><script> 等标签中的 src 属性不受跨域申请的,所以咱们是否也能够让 <script> 去申请服务器的 JS 文件来获取数据吗?

of course 当然

分为三步走:

  1. 将不同源的服务器申请地址写在 <script> 标签的src 属性中
<script src="http://127.0.0.1:3000/test"></script>
  1. 服务端响应数据必须是一个函数的调用,真正要发送给客户端的数据须要作为函数调用的参数
const data = "getData({namer:" 周深 ", song:" 大鱼 "})";
res.rend(data);  // 发送数据
  1. 全局作用域下 定义函数(两函数名要一样)
function getData(options) {alert(options.namer + '唱了一首' + options.song)
}

栗子:

客户端:

<body>
    <script>
        function getData(data) {alert(data.namer + '唱了一首' + data.song)
        }
    </script>
    <script src="http://127.0.0.1:3000/test"></script>
</body>

服务器端:

app.get('/test', function(req, res) {let data = 'getData({namer:" 周深 ", song:" 大鱼 "})'
    res.send(data)
})

JSONP 优化

第一种:把函数名通过 URL 传给服务端

咱们能够把本地函数通过 URL 传参 ?callback=getData 的形式,让服务器晓得本地函数的名字

这样的益处就是客户端批改函数名,服务器就不受影响

<script>
    function getData(data) {alert(data.namer + '唱了一首' + data.song)
    }
</script>
<script src="http://127.0.0.1:3000/test?callback=getData></script>
app.get('/test', function(req, res) {res.jsonp({ namer: '薛之谦', song: '演员'})
})

jsonp 函数曾经帮咱们做好了解决,会主动获取参数中callback 的值作为函数,所以服务端只须要传递数据即可

第二种:将 script 申请的变成动静申请

<button> 按钮 </button>

<script>
    function getData(data) {alert(data.namer + '唱了一首' + data.song)
    }
</script>

<script type="text/javascript">
    let btn = document.querySelector('button');
    btn.onclick = function() {let script = document.createElement('script');
        script.src = 'http://127.0.0.1:3000/test';
        document.body.appendChild(script);
        // 为 script 增加 onload 事件,过河拆桥
        script.onload = function() {document.body.removeChild(script)
        };
    };
</script>

发送申请的时候动态创建 script 标签发送,完结之后随即把它删除了

然而每次咱们都要写这么一坨代码吗?说这句话的时候就晓得又要疯转了

上面咱们来封装一个 jsonp 函数吧

function jsonp(options) {
    // 创立标签
    let script = document.createElement('script')

    // 拼接字符串
    let params = '';
    for (let key in options.data) {params += '&' + key + '=' + options.data[key]
    }

    // 创立随机函数,toString 将数字转换字符串去除小数点.
    let fnName = 'myFn' + Math.random().toString().replace('.', '');
    // fnName 不是全局函数,利用 window 将其变成函数
    window[fnName] = options.success;

    script.src = options.url + '?callback=' + fnName + params;
    document.body.appendChild(script)

    // 为 script 标签增加 onload 事件
    script.onload = function() {
        // 删除掉 script 标签
        document.body.removeChild(script)
    }
}

调用 jsonp(须要自行导入jsonp 函数)

<body>
    <button id="xzq"> 薛之谦 </button>
    <button id="zs"> 周深 </button>
    <script type="text/javascript">
        let btn1 = document.querySelector('#xzq');
        let btn2 = document.querySelector('#zs');
        
        btn1.onclick = function() {
            jsonp({
                url: 'http://127.0.0.1:3000/test',
                data: {
                    namer: '薛之谦',
                    song: '刚刚好'
                },
                success: function(data) {alert(data.namer + '--' + data.song);
                }
            })
        };
        
        btn2.onclick = function() {
            jsonp({
                url: 'http://127.0.0.1:3000/test',
                data: {
                    namer: '周深',
                    song: '大鱼'
                },
                success: function(data) {alert(data.namer + '--' + data.song);
                }
            })
        };
    </script>
</body>

后盾:

app.get('/test', function(req, res) {res.jsonp(req.query)
})

3.2 CORS 跨域资源共享

CORS 全称为 Cross-origin Rescourse Sharing,即跨域资源共享,是 W3C 推出的一种新的机制。

它容许浏览器向跨域服务器发送 Ajax 申请,克服了Ajax 只能同源应用的限度

所以,当咱们在应用 CORS 解决跨域申请时,浏览器判断这是一个跨域申请,会主动帮咱们解决好相应的跨域申请配置,增加一些附加头部信息,而咱们要做的仅仅是在服务器端判断是否容许这个域拜访

1、简略申请

简略申请必须满足三个申请:

  1. 申请形式为GETPOSTHEAD
  2. 数据类型 Content-Type 只能是application/x-www-form-urlencodedmultipart/form-datatext/plain
  3. 不应用自定义的申请头

所以,如果是简略申请,能够设置一个容许跨域申请的头信息

在服务端设置:

app.post('/cache', function(req, res) {res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080')
    res.send('你要始终走,直到灯火通明')
})

容许这个 http://localhost:8080 域申请,如果咱们想要任何域可能申请,只须要换成 * 即可

res.setHeader('Access-Control-Allow-Origin', '*')

当初任何所属域的 Ajax 来申请这个服务器,都会被赋予拜访权限,都能够失常响应数据了

2、预申请

域申请是一种绝对比较复杂的一些的申请,当呈现以下条件时,就会被当做预申请

  1. 申请形式是 GETPOSTHEAD以外的形式,比方:PUTDELETE
  2. 应用 POST申请,但数据类型是 application/xml 或者 text/xml 的 XML 数据类型
  3. 应用自定义的申请头信息

3、附带凭证信息的申请

XMLHttpRequest 对象在发送申请的同时会发送凭证(Cookie 和 验证信息),然而跨域申请并不会发送

所以想要传递 Cookie 给服务器,就要在申请头外面设置容许发送凭证信息。客户端和服务端都须要设置

感兴趣的话能够持续摸索 ……

总结

  1. Ajax的同源策略就是说只有协定、主机号、端口的都一样的域能力进行申请,而这样做的目标就是为了平安,避免网站信息被窃取
  2. 解决跨域申请的形式有很多,JSONP 申请的是可执行脚本,适宜用于申请咱们本人的服务器
  3. CORS 是 H5 的一种新个性,根本反对所有的申请,也是咱们罕用的,毛病就是低版本的浏览器会有兼容性问题
退出移动版