您的位置:1010cc时时彩经典版 > 1010cc时时彩客户端 > 【1010cc时时彩经典版】JSONP跨域的原理解析,浏览

【1010cc时时彩经典版】JSONP跨域的原理解析,浏览

发布时间:2019-10-07 00:48编辑:1010cc时时彩客户端浏览(156)

    谈谈前后端的分工协作

    2015/05/15 · HTML5 · 1 评论 · Web开发

    原文出处: 小胡子哥的博客(@Barret李靖)   

    前后端分工协作是一个老生常谈的大话题,很多公司都在尝试用工程化的方式去提升前后端之间交流的效率,降低沟通成本,并且也开发了大量的工具。但是几乎没有一种方式是令双方都很满意的。事实上,也不可能让所有人都满意。根本原因还是前后端之间的交集不够大,交流的核心往往只限于接口及接口往外扩散的一部分。这也是为什么很多公司在招聘的时候希望前端人员熟练掌握一门后台语言,后端同学了解前端的相关知识。

    JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same- Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档 在同一域下的内容。

    题目1: ajax 是什么?有什么作用?

    ajax(Asynchronous JavaScript and XML 异步的JavaScript与XML技术),他利用HTML.CSS.Javascript.XML以及最最最重要的XMLHttpResponse接口向后端发送http请求实现不刷新页面的情况下更新部分页面内容.
    1010cc时时彩经典版,步骤:
    1.构建ajax, xhr = new XMLHttpResponse
    2.设置发送方式.接口名字,参数. xhr.open('get','/loadMore?index=' pageIndex 'length=5',true)
    3.设置header,文件格式等参数
    4.发送HTTP请求,xhr.send()
    5.接受数据,对数据进行操作
    6.更新页面相关内容
    作用:不刷新页面的情况下,更新部分页面内容,不耽误用户其他操作,提升用户体验.

    题目1: ajax 是什么?有什么作用?

    • ajax 是什么
      AJAX全称为“Asynchronous JavaScript and XML”(异步JavaScript和XML)
      ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术
      ajax是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换。
      ajax可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
      而传统的网页(不使用ajax)如果需要更新内容,必须重载整个网页面。
    • ajax的作用:
      1、最大的一点是页面无刷新,用户的体验非常好。
      2、使用异步方式与服务器通信,具有更加迅速的响应能力。。
      3、可以把以前一些服务器负担的工作转嫁到客户端,利用客户端闲置的能力来处理,减轻服务器和带宽的负担,节约空间和宽带租用成本。并且减轻服务器的负担,ajax的原则是“按需取数据”,可以最大程度的减少冗余请求,和响应对服务器造成的负担。
      4、基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。

    本文先简要介绍前端开发中的浏览器同源政策;然后在跨域问题中,具体介绍跨域ajax请求的应用场景与实现方案。

    一、开发流程

    前端切完图,处理好接口信息,接着就是把静态demo交给后台去拼接,这是一般的流程。这种流程存在很多的缺陷。

    • 后端同学对文件进行拆分拼接的时候,由于对前端知识不熟悉,可能会搞出一堆bug,到最后又需要前端同学帮助分析原因,而前端同学又不是特别了解后端使用的模板,造成尴尬的局面。
    • 如果前端没有使用统一化的文件夹结构,并且静态资源(如图片,css,js等)没有剥离出来放到 CDN,而是使用相对路径去引用,当后端同学需要对静态资源作相关配置时,又得修改各个link,script标签的src属性,容易出错。
    • 接口问题
      1. 后端数据没有准备好,前端需要自己模拟一套,成本高,如果后期接口有改变,自己模拟的那套数据又不行了。
      2. 后端数据已经开发好,接口也准备好了,本地需要代理线上数据进行测试。这里有两个费神的地方,一是需要代理,否则可能跨域,二是接口信息如果改动,后期接你项目的人需要改你的代码,麻烦。
    • 不方便控制输出。为了让首屏加载速度快一点,我们期望后端先吐出一点数据,剩下的才去 ajax 渲染,但让后端吐出多少数据,我们不好控。

    当然,存在的问题远不止上面枚举的这些,这种传统的方式实在是不酷(Kimi 附身^_^)。还有一种开发流程,SPA(single page application),前后端职责相当清晰,后端给我接口,我全部用 ajax 异步请求,这种方式,在现代浏览器中可以使用 PJAX 稍微提高体验,Facebook 早在三四年前对这种 SPA 的模式提出了一套解决方案,quickling bigpipe,解决了 SEO 以及数据吐出过慢的问题。他的缺点也是十分明显的:

    • 页面太重,前端渲染工作量也大
    • 首屏还是慢
    • 前后端模板复用不了
    • SEO 依然很狗血(quickling 架构成本高)
    • history 管理麻烦

    问题多的已经是无力吐槽了,当然他依然有自己的优势,咱们也不能一票否决。

    针对上面看到的问题,现在也有一些团队在尝试前后端之间加一个中间层(比如淘宝UED的 MidWay )。这个中间层由前端来控制。

    JavaScript

    ---------------- | F2E | ---↑--------↑--- | | ---↓--------↓--- | Middle | ---↑--------↑--- | | ---↓--------↓--- | R2E | ----------------

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
         ----------------
        |       F2E      |
         ---↑--------↑---
            |        |
         ---↓--------↓---
        |     Middle     |
         ---↑--------↑---
            |        |  
         ---↓--------↓---
        |       R2E      |
         ----------------

    中间层的作用就是为了更好的控制数据的输出,如果用MVC模型去分析这个接口,R2E(后端)只负责 M(数据) 这部分,Middle(中间层)处理数据的呈现(包括 V 和 C)。淘宝UED有很多类似的文章,这里不赘述。

    JavaScript这个安全策略在进行多iframe或多窗口编程、以及Ajax编程时显得尤为重要。根据这个策略,在baidu.com下的 页面中包含的JavaScript代码,不能访问在google.com域名下的页面内容;甚至不同的子域名之间的页面也不能通过JavaScript代 码互相访问。对于Ajax的影响在于,通过XMLHttpRequest实现的Ajax请求,不能向不同的域提交请求,例如,在 abc.example.com下的页面,不能向def.example.com提交Ajax请求,等等。

    题目2: 前后端开发联调需要注意哪些事情?后端接口完成前如何 mock 数据?

    注意事项:大的方面我需要什么,我给你什么.具体来讲:
    1.约定后端发回的数据格式.数组.JSON.文本.二进制文件
    2.约定请求方式:post或者get
    3.约定接口名字/路径
    4.约定发送的参数
    mock数据
    要完整运行前端代码,通常并不需要完整的后端环境,我们只要在mock server中实现以下几点就行了:

    • 能渲染模板
    • 实现请求路由映射
    • 数据接口代理到生产或者
    ![](https://upload-images.jianshu.io/upload_images/5927991-9f59e15fb04d32f8.png)
    
    image.png
    
    
    
    测试环境
    

    参考

    题目2:前后端开发联调需要注意哪些事情?后端接口完成前如何 mock 数据?

    • 前后端联调是一种 真实业务数据 和 本地mock数据 之间来回切换以达到 前后端分离架构 下的不同开发速度时 数据交换 的一种方式方法。

    • 注意事项:
      1.确定要传输的数据以及数据类型。
      2.确定接口名称、请求和响应的类型格式(get或是post)
      3.请求的数据中参数的名称

      如: { index:3
          length:5  }
      

      4.响应的数据的格式。如JSON格式的字符串

    • 后端接口完成前如何 mock 数据
      mock数据:当后端接口没有完成前,前端需要模仿后台数据,以测试处理前端的请求。
      1.使用nodejs搭建一个web服务器,返回我们想要的数据
      2.安装server-mock,在当前的文件夹下创建 router.js,接受处理请求数据

    什么是同源策略

    如果你进行过前端开发,肯定或多或少会听说过、接触过所谓的同源策略。那么什么是同源策略呢?

    要了解同源策略,首先得理解“源”。在这个语境下,源(origin)其实就是指的URL。所以,我们需要先理解URL的组成。看看这个URL:
    http://www.jianshu.com/p/bc7b8d542dcd

    我们可以将它拆解为下面几个部分协议、域名和路径:

    http       :// www.jianshu.com    /p/bc7b8d542dcd
    ${protocol}:// ${hostname}         ${pathname}
    

    而对于一个更为完整的URLhttp://www.jianshu.com:80/p/bc7b8d542dcd#sample?query=text

    protocol host port pathname hash query string
    http www.jianshu.com 80 /p/bc7b8d542dcd sample query=text
    location.protocol location.host location.port location.pathname location.hash location.search

    而同源就是指URL中protocol协议、host域名、port端口这三个部分相同。

    下表是各个URL相对于http://www.jianshu.com/p/bc7b8d542dcd的同源检测结果

    URL 是否同源 非同源原因
    http://www.jianshu.com/p/0b2acb50f321
    https://www.jianshu.com/p/0b2acb50f321 不同协议
    http://www.jianshu.com:8080/p/0b2acb50f321 不同端口
    http://www.jianshu2.com/p/0b2acb50f321 不同域名

    因此,简单来说,同源策略就是浏览器出于网站安全性的考虑,限制不同源之间的资源相互访问的一种政策。以下操作具有同源策略的限制:

    • AJAX 请求不能发送。
    • 无法获取DOM元素并进行操作。
    • 无法读取Cookie、LocalStorage 和 IndexDB 。

    而本文就会针对跨域AJAX场景及其各种常见解决方案进行相关介绍。

    值得一提的是,有些请求是不受到跨域限制。例如:WebSocket,script、img、iframe、video、audio标签的src属性等。

    二、核心问题

    上面提出了在业务中看到的常见的三种模式,问题的核心就是数据交给谁去处理。数据交给后台处理,这是模式一,数据交给前端处理,这是模式二,数据交给前端分层处理,这是模式三。三种模式没有优劣之分,其使用还是得看具体场景。

    既然都是数据的问题,数据从哪里来?这个问题又回到了接口。

    • 接口文档由谁来撰写和维护?
    • 接口信息的改动如何向前后端传递?
    • 如何根据接口规范拿到前后端可用的测试数据?
    • 使用哪种接口?JSON,JSONP?
    • JSONP 的安全性问题如何处理?

    这一系列的问题一直困扰着奋战在前线的前端工程师和后端开发者。淘宝团队做了两套接口文档的维护工具,IMS以及DIP,不知道有没有对外开放,两个东西都是基于 JSON Schema 的一个尝试,各有优劣。JSON Schema 是对 JSON 的一个规范,类似我们在数据库中创建表一样,对每个字段做一些限制,这里也是一样的原理,可以对字段进行描述,设置类型,限制字段属性等。

    接口文档这个事情,使用 JSON Schema 可以自动化生产,所以只需编写 JSON Schema 而不存在维护问题,在写好的 Schema 中多加些限制性的参数,我们就可以直接根据 Schema 生成 mock(测试) 数据。

    mock 数据的外部调用,这倒是很好处理:

    JavaScript

    typeof callback === "function" && callback({ json: "jsonContent" })

    1
    2
    3
    typeof callback === "function" && callback({
       json: "jsonContent"
    })

    在请求的参数中加入 callback 参数,如 /mock/hashString?cb=callback,一般的 io(ajax) 库都对异步数据获取做了封装,我们在测试的时候使用 jsonp,回头上线,将 dataType 改成 json 就行了。

    JavaScript

    IO({ url: "", dataType: "jsonp", //json success: function(){} })

    1
    2
    3
    4
    5
    IO({
      url: "http://barretlee.com",
      dataType: "jsonp", //json
      success: function(){}
    })

    这里略微麻烦的是 POST 方法,jsonp 只能使用 get 方式插入 script 节点去请求数据,但是 POST,只能呵呵了。

    这里的处理也有多重方式可以参考:

    • 修改 Hosts,让 mock 的域名指向开发域名
    • mock 设置 header 响应头,Access-Allow-Origin-Control

    对于如何拿到跨域的接口信息,我也给出几个参考方案:

    • fiddler 替换包,好像是支持正则的,感兴趣的可以研究下(求分享研究结果,因为我没找到正则的设置位置)
    • 使用 HTTPX 或者其他代理工具,原理和 fiddler 类似,不过可视化效果(体验)要好很多,毕竟人家是专门做代理用的。
    • 自己写一段脚本代理,也就是本地开一个代理服务器,这里需要考虑端口的占用问题。其实我不推荐监听端口,一个比较不错的方案是本地请求全部指向一个脚本文件,然后脚本转发URL,如:

    JavaScript

    原始请求: 在ajax请求的时候: $.ajax({ url: "" });

    1
    2
    3
    4
    5
    原始请求:http://barretlee.com/api/test.json
    在ajax请求的时候:
    $.ajax({
      url: "http://<local>/api.php?path=/api/text.json"
    });
    • php中处理就比较简单啦:

    JavaScript

    if(!isset($_GET["page"])){ echo 0; exit(); } echo file_get_contents($_GET["path"]);

    1
    2
    3
    4
    5
    if(!isset($_GET["page"])){
      echo 0;
      exit();
    }
    echo file_get_contents($_GET["path"]);
    • Ctrl S,保存把线上的接口数据到本地的api文件夹吧-_-||

    然而,当进行一些比较深入的前端编程的时候,不可避免地需要进行跨域操作,这时候“同源策略”就显得过于苛刻。JSONP跨域GET请求是一个常用的解决方案,下面我们来看一下JSONP跨域是如何实现的,并且探讨下JSONP跨域的原理。

    题目3:点击按钮,使用 ajax 获取数据,如何在数据到来之前防止重复点击?

    增加一个状态锁.具体在题目4实现
    参考

    题目3:点击按钮,使用 ajax 获取数据,如何在数据到来之前防止重复点击?

    解决思路: 阻止用户的重复点击,第一次点击时请求的数据该没到之前,其他的点击操作无效,被忽略
    设计一个状态锁,实时监看响应数据的情况,默认为有已经有响应。
    当点击按钮时,判断请求是不是响应了,没有响应,则不会做任何操作;

    var isDataArrive=true;//状态锁  默认现在是有响应数据
    var btn=document.querySelector('#btn')
    var pageIndex=3;
    
     btn.addEventListener('click', function(e){
       e.preventDefault()
       if(!isDataArrive){   //判断是不是响应了,没响应,退出
         return;
     }
     var xhr = new XMLHttpRequest()
     xhr.onreadystatechange = function(){
         if(xhr.readyState === 4){
             if( xhr.status === 200 || xhr.status == 304){
                 var results = JSON.parse(xhr.responseText)
                 console.log(results)
                 var fragment = document.createDocumentFragment()
                 for(var i = 0; i < results.length; i  ){
                     var node = document.createElement('li')
                     node.innerText = results[i]
                     fragment.appendChild(node)
                 }
                 content.appendChild(fragment)
                 pageIndex = pageIndex   5
             }else{
                 console.log('出错了')
             }
             isDataArrive = true   //当前表示是响应数据状态
         }
     }
     xhr.open('get', '/loadMore?index=' pageIndex '&length=5', true)
     xhr.send()
     isDataArrive = false  //做完数据处理,响应数据后,恢复到没有响应数据状态
     })
    

    为什么实际开发中会有跨域ajax请求

    根据上文的内容我们可以知道,由于浏览器同源政策的影响,跨域的ajax请求是不被允许。那么在实际的开发、应用中,是否有跨域ajax的场景呢?

    答案是肯定的。

    那么有哪些场景会有跨域ajax的需求呢?

    1. 当你调用一个现有的API或公开API:想象一下,你接到了一个新需求,需要在当前开发的新闻详细页http://www.yournews.com/p/123展示该新闻的相关推荐。令人欣慰的是,推荐的接口已经在你们公司的其他产品线里实现了,你只需要给该接口一个query即可:http://www.mynews.com/recommend?query=123。然而问题来了——你发起了一个跨域请求。

    2. 前后端分离的开发模式下,在本地进行接口联调时:也许在你的项目里,你想尝试前后端分离的开发模式。你在本地开发时,mock了一些假数据来帮助自己本地开发。而有一天,你希望在本地和后端同学进行联调。此时,后端rd的接口地址和你发生了跨域问题。这阻止了你们的联调,你只能继续使用你mock的假数据。

    上面只是列举了存在跨域的两个最为常见的场景,这足以说明跨域请求在实际开发中确实经常出现。

    三、小结

    本文只是对前后端协作存在的问题和现有的几种常见模式做了简要的列举,JSON Schema 具体如何去运用,还有接口的维护问题、接口信息的获取问题没有具体阐述,这个后续有时间会整理下我对他的理解。

    赞 2 收藏 1 评论

    1010cc时时彩经典版 1

    利用在页面中创建<script>节点的方法向不同域提交HTTP请求的方法称为JSONP,这项技术可以解决跨域提交Ajax请求的问题。JSONP的工作原理如下所述:

    题目4:实现加载更多的功能,效果范例338,后端在本地使用server-mock来模拟数据

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-6">
        <title>load-more</title>
    
        <style>
            a{
                text-decoration: none;
            }
            .ct {
                margin: 0;
                padding: 0;
                vertical-align: middle;
                text-align: center;
            }
            .ct li{
                list-style: none;
                border: 1px solid red;
                padding: 10px;
                margin: 10px 20px;
                color: blue;
                cursor: pointer;
                border-radius: 4px;
            }
            .ct li:hover {
                background-color: green;
                color: azure;
            }
            .btn-ct {
                text-align: center;
            }
            .btn {
                display: inline-block;
                margin: 20px auto;
                padding: 10px;
                background: yellowgreen;
                font-size: 18px;
                color: red;
                border-radius: 5px;
    
            }
            .btn:hover {
                background-color: deepskyblue;
                color: firebrick;
            }
        </style>
    </head>
    <body>
        <ul class="ct">
            <li>新闻0</li>
        </ul>
        <div class="btn-ct"><a  href="##" class="btn">加载更多</a></div>
    </body>
    <script>
        var ct = document.querySelector('.ct')
        var btn = document.querySelector('.btn')
        var pageIndex = 1
        var dataArrive = true//状态锁,防止重复点击
        function loadMore(){
            if(dataArrive === false){//用来判断是否为重复无效点击
                return
            }
            dataArrive = false
            var xhr = new XMLHttpRequest()
            xhr.onreadystatechange = function(){
                if (xhr.readyState === 4){
                    if (xhr.status === 200 || xhr.status === 304){
                        console.log(xhr.responseText)
                        var results = JSON.parse(xhr.responseText)
                        console.log(results.length)
                        var fragment = document.createDocumentFragment()
                        for(var i = 0;i < results.length; i  ){
                            console.log(i)
                            var node = document.createElement('li')
                            node.innerText = results[i]
                            fragment.appendChild(node)
                            pageIndex  = 1;
                        }
                        ct.appendChild(fragment)
                    }else{
                        console.log('error')
                    }
                    dataArrive = true
                }
            }
            xhr.open('get','/loadMore?index=' pageIndex '&length=5',true)
            xhr.send()
        }
        btn.addEventListener('click',loadMore)
    </script>
    </html>
    
    // 服务端 router.js
    
    
    app.get('/loadMore', function(req, res) {
    
      var curIdx = req.query.index
      var len = req.query.length
      var data = []
    
      for(var i = 0; i < len; i  ) {
        data.push('新闻'   (parseInt(curIdx)   i))
      }
    
      setTimeout(function(){
        res.send(data);
      },3000)
    
    });
    

    题目4:实现加载更多的功能,效果范例380,后端在本地使用server-mock来模拟数据

    github代码

    跨域的一些方案

    了解了上面的内容后,下面就来介绍一下在实践中常用的三种ajax跨域方案。这部分的实例代码可以在这里看到:cross-domain-demo

    假设这样一个跨域场景:目前有两个项目

    • myweb,这个就是我们目前开发的项目,是一个独立的站点。
    • thirdparty,表示我们需要调用到的第三方(third-party)后端服务,myweb项目就是需要调用它的接口。

    为了简化不必要的代码编写过程,示例使用express-generator来快速生成myweb与thirdparty这两个应用,其中thirdparty我们只需要用到后端接口部分。

    npm install express-generator -g
    express --view=pug myweb
    express --view=pug thirdparty
    

    在myweb中,index页面 http://127.0.0.1:8085需要跨域访问server中的http://127.0.0.1:3000/info/normal这个接口的信息。前端操作是:当点击button时就会去获取info,并alert出来。
    跨域访问的接口http://127.0.0.1:3000/info/normal代码如下:

    const express = require('express');
    const router = express.Router();
    
    const data = {
        name: 'alienzhou',
        desc: 'a developer'
    };
    
    router.get('/normal', (req, res, next) => {
        res.json(data);
    });
    

    然后是http://127.0.0.1:8085index页面的部分的javascript

    // http://127.0.0.1:8085  -- index.js
    document.getElementById('btn-1').addEventListener('click', function() {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4 && xhr.status === 200) {
                alert(xhr.responseText);
            }
        }
        xhr.open('get', 'http://127.0.0.1:3000/info/normal');
        xhr.send(null);
    });
    

    点击btn-1,在控制台中就会出现如下错误,这个跨域ajax请求受到了同源策略的限制。

    [Error] Origin http://127.0.0.1:8085 is not allowed by Access-Control-Allow-Origin.
    [Error] Failed to load resource: Origin http://127.0.0.1:8085 is not allowed by Access-Control-Allow-Origin. (normal, line 0)
    [Error] XMLHttpRequest cannot load http://127.0.0.1:3000/info/normal due to access control checks.
    

    下面来讲具体的三种解决方案:

    本文由1010cc时时彩经典版发布于1010cc时时彩客户端,转载请注明出处:【1010cc时时彩经典版】JSONP跨域的原理解析,浏览

    关键词:

上一篇:偶然比,剖判中间人抨击之SSL欺诈

下一篇:没有了