解决前端跨域请求的几种方式

利用 JSONP 实现跨域调用前端

说道跨域调用,可能你们首先想到的或者据说过的就是 JSONP 了。jquery

1.1 什么是JSONP

JSONP 是 JSON 的一种使用模式,能够解决主流浏览器的跨域数据访问问题。其原理是根据 XmlHttpRequest 对象受到同源策略的影响,而 <script> 标签元素却不受同源策略影响,能够加载跨域服务器上的脚本,网页能够从其余来源动态产生 JSON 资料。用 JSONP 获取的不是 JSON 数据,而是能够直接运行的 JavaScript 语句。ajax

1.2 使用 jQuery 集成的 $.ajax 实现 JSONP 跨域调用

下面的例子,咱们将 服务器 3000 上的请求页面的 JavaScript 代码为:json

// 回调函数
function jsonpCallback(data) {
    console.log("jsonpCallback: " + data.name)
}
$("#submit").click(function() {
    var data = {
        name: $("#name").val(),
        id: $("#id").val()
    };
    $.ajax({
        url: 'http://localhost:3001/ajax/deal',
        data: data,
        dataType: 'jsonp',
        cache: false,
        timeout: 5000,
        // jsonp 字段含义为服务器经过什么字段获取回调函数的名称
        jsonp: 'callback',
        // 声明本地回调函数的名称,jquery 默认随机生成一个函数名称
        jsonpCallback: 'jsonpCallback',
        success: function(data) {
            console.log("ajax success callback: " + data.name)
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(textStatus + ' ' + errorThrown);
        }
    });
});

 服务器 3001 上对应的处理函数为:跨域

1 app.get('/ajax/deal', function(req, res) {
2     console.log("server accept: ", req.query.name, req.query.id)
3     var data = "{" + "name:'" + req.query.name + " - server 3001 process'," + "id:'" + req.query.id + " - server 3001 process'" + "}"
4     var callback = req.query.callback  //得到请求端回调函数
5     var jsonp = callback + '(' + data + ')'
6     console.log(jsonp)
7     res.send(jsonp)
8     res.end()
9 })

这里必定要注意 data 中字符串拼接,不能直接将 JSON 格式的 data 直接传给回调函数,不然会发生编译错误: parsererror Error: jsonpCallback was not called浏览器

 

1.3 使用 <script> 标签原生实现 JSONP

通过上面的事件,你是否是以为 JSONP 的实现和 Ajax 大同小异?服务器

其实,因为实现的原理不一样,由 JSONP 实现的跨域调用不是经过 XmlHttpRequset 对象,而是经过 script 标签,因此在实现原理上,JSONP 和 Ajax 已经一点关系都没有了。看上去形式类似只是因为 jQuery 对 JSONP 作了封装和转换。app

好比在上面的例子中,咱们假设要传输的数据 data 格式以下:cors

{
    name: "chiaki",
    id": "3001"
}

那么数据是如何传输的呢?HTTP 请求头的第一行以下:函数

GET /ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032 HTTP/1.1

可见,即便形式上是用 POST 传输一个 JSON 格式的数据,其实发送请求时仍是转换成 GET 请求。

其实若是理解 JSONP 的原理的话就不难理解为何只能使用 GET 请求方法了。因为是经过 script 标签进行请求,因此上述传输过程根本上是如下的形式:

    
<script src = 'http://localhost:3001/ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>

这样从服务器返回的代码就能够直接在这个 script 标签中运行了。下面咱们本身实现一个 JSONP:

  • 服务器 3000请求页面的 JavaScript 代码中,只有回调函数 jsonpCallback:

  • function jsonpCallback(data) {
        console.log("jsonpCallback: "+data.name)
    }

    服务器 3000请求页面还包含一个 script 标签:

  • <script src = 'http://localhost:3001/jsonServerResponse?jsonp=jsonpCallback'></script>

    服务器 3001上对应的处理函数:

    1 app.get('/jsonServerResponse', function(req, res) {
    2     var cb = req.query.jsonp //这里获得请求页面的回调函数
    3     console.log(cb)
    //思考一下为何这里要这样写
    4 var data = 'var data = {' + 'name: $("#name").val() + " - server 3001 jsonp process",' + 'id: $("#id").val() + " - server 3001 jsonp process"' + '};' 5 var debug = 'console.log(data);' //打印var data=""; 6 var callback = '$("#submit").click(function() {' + data + cb + '(data);' + debug + '});' 7 res.send(callback) //返回的是一个点击按钮的事件 8 res.end() 9 })

    与上面同样,咱们在所获取的参数后面加上 “ - server 3001 jsonp process” 表明服务器对数据的操做。从代码中我么能够看到,处理函数除了根据参数作相应的处理,更多的也是进行字符串的拼接。

  • 2.4 JSONP 总结

    至此,咱们了解了 JSONP 的原理以及实现方式,它帮咱们实现前端跨域请求,可是在实践的过程当中,咱们仍是能够发现它的不足:

    1. 只能使用 GET 方法发起请求,这是因为 script 标签自身的限制决定的。
    2. 不能很好的发现错误,并进行处理。与 Ajax 对比,因为不是经过 XmlHttpRequest 进行传输,因此不能注册 success、 error 等事件监听函数
    3. 使用 CORS 实现跨域调用

      3.1 什么是 CORS?

      Cross-Origin Resource Sharing(CORS)跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不一样域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不一样,CORS 除了 GET 要求方法之外也支持其余的 HTTP 要求。用 CORS 可让网页设计师用通常的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另外一方面,JSONP 能够在不支持 CORS 的老旧浏览器上运做。现代的浏览器都支持 CORS。

    4. 3.2 CORS 的实现

      仍是以 服务器 3000 上的请求页面向 服务器 3001 发送请求为例。

      • 服务器 3000 上的请求页面 JavaScript 不变,服务器 3001上对应的处理函数:

      •  1 app.post('/cors', function(req, res) {
         2     res.header("Access-Control-Allow-Origin", "*"); //设置请求来源不受限制
         3     res.header("Access-Control-Allow-Headers", "X-Requested-With");  
         4     res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); //请求方式
         5     res.header("X-Powered-By", ' 3.2.1')
         6     res.header("Content-Type", "application/json;charset=utf-8");
         7     var data = {
         8         name: req.body.name + ' - server 3001 cors process',
         9         id: req.body.id + ' - server 3001 cors process'
        10     }
        11     console.log(data)
        12     res.send(data)
        13     res.end()
        14 })

        3.3 CORS 中属性的分析

        1. Access-Control-Allow-Origin

          The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify “*” as a wildcard, thereby allowing any origin to access the resource.

        2. Access-Control-Allow-Methods

          Specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.

        3. Access-Control-Allow-Headers

          Used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

          3.4 CORS 与 JSONP 的对比

          1. CORS 除了 GET 方法外,也支持其它的 HTTP 请求方法如 POST、 PUT 等。
          2. CORS 可使用 XmlHttpRequest 进行传输,因此它的错误处理方式比 JSONP 好。
          3. JSONP 能够在不支持 CORS 的老旧浏览器上运做。
相关文章
相关标签/搜索