JS跨域请求(script标签)和JQuery跨域请求(jsonp)

蓝咒 提交于 2019-11-28 20:42:55

前言:

为尽可能保证浏览器端安全,浏览器会遵循SOP协议,即同源协议

ajax无法完成跨域请求

$.get $.post $.ajax都不可以

jsonp作为ajax的一种扩展协议可以完成跨域请求

$.getJson()也可以完成跨域请求(当然不跨域也可以)

日常开发中会经常遇到前端跨域访问请求数据的场景

比如

www.server.com 
img.server.com

当用户在www下浏览时需要获取指定记录id的图片,则我们需要在www的域下请求img域下的数据,常规情况下浏览器会处于安全控制限制无法完成跨域请求,但页面中的script或iframe标签是可以载入跨域请求的(link img也可以)

实现方式:

===============================================================

服务端

看网上很多讲跨域的都只是说了下前端如何编码,对后端的处理只字未提,虽然后端的处理很简单,但后端的处理才是点睛之笔,返回一个前端的调用函数语句,这就是传说中的回调函数

<?php
    if (isset($_GET['callback'])) {
        $callback = $_GET['callback'];
        $resultArr = [];
        $resultArr['id'] = $_GET['id'];
        $resultArr['img'] = "http://img.server.com/upload/img/201511031319.png";
        $resultJson = json_encode($resultArr);
        //callback({id:1, img:....}) 组装成调用js函数的格式 客户端载入自然触发其本地定义的回调函数
        echo $callback . "({$resultJson})";
        exit();     
    } //因为是被script标签请求载入的,所以返回的数据会包在script中,自然就触发了callback函数

===============================================================

1、JS script方式

其实原理很简单

1、在当前域下我定义一个函数作为回调函数

2、组建一个script标签元素节点,设置src为跨域请求的某API的url地址,同时此url地址中务必填写上回调函数名参数

3、将script标签挂载到文档流中,会跨域请求载入,变相的访问了跨域API,触发了API的方法,返回的数据被填充到script标签中,如果返回的是一个当前域下定义好的函数,那自然就触发处理相关数据了

4、跨域完成

在www下定义回调函数callback

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script type="text/javascript" src="http://www.yii.com/a.js"></script>
</head>
<body>
<button onclick="request()">click here</button>
    <script type="text/javascript">
    //回调函数callback定义
    //服务端输出的数据为 callback({key1:data1, key2;data2}) 到本页面 即调用此定义好的函数
    function callback(json) {
        for (i in json) {
            alert(i + ":" + json[i]);
        }
        if (json.tagId) {
            var tagId = document.getElementById(json.tagId);
            tagId.parentNode.removeChild(tagId);
        }
    }
    //发起跨域请求
    function request() {
        //利用script标签可跨域访问的特性
        var script = document.createElement('script');
        script.id = Math.random();
        script.type = 'text/javascript';
        //跨域 将callback函数名称传递给跨域服务器 服务端利用此函数名组建
        script.src = "http://img.server.com/index.php?callback=callback&id=1&tagId=" + script.id;
        //将可跨域请求的script标签挂载到head标签上
        document.getElementsByTagName("head")[0].appendChild(script);
    }
    </script>
</body>
</html>

 

===============================================================

2、jsonp方式

jsonp是ajax的扩展,严格的说它已经不是ajax,只是复用ajax的某些控制流程,封装我们上面说的js方式

重点:

dataType:'jsonp' //指定使用jsonp方式

jsonp:'callback' //回调函数的键名 传递给服务器时服务器通过此键名获取应该返回调用的函数名

jsonpCallback:'myCallback' //回调函数名不随机,自定义一个

<script type="text/javascript" >
    //其实jquery会组合成这样的请求
    //http://img.server.com/index.php?callback=myCallback&id=1
    $.ajax({
        async: false,
        type: 'get',
        url: "http://img.server.com/index.php?id=1",
        //指定为jsonp方式
        dataType: 'jsonp',
        //回调函数的键值名,即服务端通过此键值访问传递的回调函数名
        jsonp: 'callback',
        //回调函数名,若不指定则jquery会随机生成一个
        jsonpCallback: 'myCallback',
        success: function(result) {
            for (var i in result) {
                alert(i + ":" + result[i]);
            }
        },
        timeout: 3000
    });
    //Jquery会根据你指定的jsonpCallback参数在本地生成一个
    //function myCallback(result) {
        //这样就调用了success方法
        //this.success(result);
    //} 
</script>

===============================================================

3、getJSON

重点:

一定要在url中写上callback=?,只有这样才会在本地生成一个回调函数,跨域的后端通过callback获取到此函数名,进行回调

<script type="text/javascript" >
    //其实jquery会组合成这样的请求
    //http://img.server.com/index.php?callback=myCallback&id=1
    var url = "http://img.server.com/index.php?callback=?"; //记住一定要有callback=?
    var data = {'id':1};
    $.getJSON(
        url,
        data,
        function(result){
            for (var i in result) {
                alert(i + ":" + result[i]);
            }
        });
</script>

===============================================================

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!