zoukankan      html  css  js  c++  java
  • 跨域 Ajax 其他可选技术 异步

    使用image pings
    最早的跨域方法之一就是使用这个,任何域的<img>和<script>元素都可以随便加载。
    var img = new Image();
    img.onload = img.onerror = function(){
    alert(“Done!”);
    };
    img.src = “http://www.example.com/test?name=Nicholas”;
    数据通过查询字符串的形式发送,返回的可能是任何东西,通常是一像素的图片或者204响应。缺点就是只能使用get方式并且无法获得响应数据。所以通常用于单向从浏览器发送数据给服务器。
     
    JSONP(动态生成script)
    全称JSON with padding  ,是JSON的变形,它看起来就像JSON除了数据被一个函数调用的东西包裹着:
    callback({ “name”: “Nicholas” });
    当收到响应的时候,就会调用页面上的callback函数。因为JSONP是有效的JavaScript,当JSONP的响应输出到页面上后就会立刻执行。
    function handleResponse(response){
    alert(“You’re at IP address “ + response.ip + “, which is in “ +
    response.city + “, “ + response.region_name);
    }
    var script = document.createElement(“script”);
    script.src = “http://freegeoip.net/json/?callback=handleResponse”;
    document.body.insertBefore(script, document.body.firstChild);
     
    比起用image,可以从响应里获得数据了。问题是可以注入邪恶脚本。其次是很难检测是否失败了,虽然HTML5给script定义了onerror事件,但浏览器支持不好。只能用定时检测在一段时间里是否受到了响应
     
    Comet
    服务器给页面推送数据,而不是页面向服务器请求数据,这种方式让信息能够更接近实时,例如比赛分数,股票价格等。
    comet有实现两种方式,long polling和streaming
     
    long polling
    相对于传统的polling(short polling),浏览器定时请求服务器看有没有新数据,服务器不管有没有可用数据都马上返回响应。而long polling等待有可用数据的时候才返回响应,浏览器收到响应后马上发起新的请求。
    优点就是使用xhr对象配合setTimeOut就可以了。只需要管理什么时候发送请求。
     
    第二种方式是HTTP streaming
    它是指使用单一个请求在整个页面的生存周期里,浏览器向服务器发送一个请求然后服务器保持这个链接不断,周期性地向浏览器推送数据。因为服务器端的语言都支持把数据写到输出缓存里,然后flush给客户端,因此这就是HTTP streaming的核心了。
     
    举例:
    function createStreamingClient(url, progress, finished){
    var xhr = new XMLHttpRequest(),
    received = 0;
    xhr.open(“get”, url, true);
    xhr.onreadystatechange = function(){
    var result;
    if (xhr.readyState == 3){
    //get only the new data and adjust counter
    result = xhr.responseText.substring(received);
    received += result.length;
    //call the progress callback
    progress(result);
    } else if (xhr.readyState == 4){
    finished(xhr.responseText);
    }
    };
    xhr.send(null);
    return xhr;
    }
    var client = createStreamingClient(“streaming.php”, function(data){
    alert(“Received: “ + data);
    }, function(data){
    alert(“Done!”);
    });

    通过监听readystate为3来达到目的,IE不支持,但是对链接的管理很容易出错和对时间点要求高。浏览器开发商认为comet是未来Web世界的重要组成部分,因此推出了两个新的接口,让comet更加友好
    1、server-sent events
    这是一个针对只读comet交互的接口,这个接口建立了和服务器的单向链接(当然你可以配合xhr来实现双向通信),服务器响应的时候必须包含一个MIME类型为text/event-stream,输出的信息以一种指定的给浏览器。这个接口支持short polling,long polling和HTTP streaming,它会自动重新连接当原连接断开时。
     
    var source = new EventSource(“myevents.php”);
    地址必须是同域的,和调用该对象所在域一致,该对象实例也有readystate属性:
    0  代表正在连接服务器
    1  代表链接打开
    2  代表链接关闭
     
    有三个事件:
    open  当链接建立时触发
    message  当从服务器收到新事件时触发
    error     当无法建立连接触发
    source.onmessage = function(event){
    var data = event.data;   从服务器传回来的信息以字符串的形式保存在data属性里
    //do something with the data
    };
    默认地,当和服务器的连接被关闭, EventSource 会重新连接,可以通过close方法断开连接,禁止重新连接
    source.close();
     
    服务器发送的事件带上MIME类型为 text/event-stream,以long-lasting HTTP响应返回。
     
    格式如下:
    data: foo
     
    data: bar
     
    data: foo
    data: bar
     
    每一个空格代表发送一个message事件,例如第三个message事件event.data 值为 “foo bar”
     
    可以指定给事件加个ID标识:
    data:foo
    id: 1
     
    这样在多个连接情况下,断开重连也能找到之前的位置咯
     
     
    2、Web socket
    目的是通过一个long-lasting链接来实现浏览器和客户端的双向沟通。
    当建立这种连接的时候,一个HTTP请求发送给服务器初始化一个链接,当服务器响应时,该连接会从HTTP升级为Web socket协议。这意味着服务器需要是支持Web socket 协议的。
    web socket普通连接为  ws://
    安全连接为  wss://
     
    好处是发送很小的数据,不受HTTP字节妨碍,使用小数据包让Web socket在移动应用很适合。
    var socket = new WebSocket("ws://www.haha.com/server.php");
     
    必须传入绝对地址,可以跨域,完全由服务器决定是否和请求域建立连接。
     
    浏览器会尝试建立连接当WebSocket对象被实例化以后。类似xhr,它也有一个readystate属性,只是值不同:
    0   正在建立连接
    1   连接已经建立好
    2   连接开始关闭
    3   连接已经关闭
     
    Websocket是没有readystatechange事件的,但有相对不同状态的处理事件。你可以使用close来关闭链接
    socket.close();
    调用close,readystate马上变为2最后变为3
     
    发送数据给服务器:
    socket.send(“haha");
    因为Web socket只能发送plain text,你需要把复杂数据结构先序列化:
    var message = {
    time: new Date(),
    text: “Hello world!”,
    clientId: “asdfp8734rew”
    };
    socket.send(JSON.stringify(message));
     
    当服务器像客户端发送信息时,会触发message事件,返回的数据也是字符串,需要手动解析:
    socket.onmessage = function(event){
    var data = event.data;
    //do something with data
    };
     
    Web socket只能用Dom 0事件添加方式:
    socket.onopen = function(){
        alert(“Connection established.”);
    };
    socket.onerror = function(){
         alert(“Connection error.”);
    };
    socket.onclose = function(){
         alert(“Connection closed.”);
    };
     
    只有close事件有额外信息在event对象里:
    wasClean属性:   布尔值,表示链接是否被干净地关掉
    code:服务器返回的状态代码,数字
    season:服务器发送的字符串
     
    socket.onclose = function(event){
    console.log(“Was clean? “ + event.wasClean + “ Code=” + event.code + “ Reason=”
    + event.reason);
    };
     
    安全问题
    1、浏览器和服务器可以接入修改URL,例如:/getuserinfo.php?uid=6,没办法阻止别人把uid改成别的,因此 getuserinfo.php需要做进一步验证
     
    2、当一个未经授权的系统能够进来获取资源的时候,就意味着发生了跨网站请求伪造(csrf)攻击。
    预防就是验证该请求发送发之前接入过这个资源:
    方法1:要求请求资源时带有SSL证书
    方法2:要求每个请求带上一个用来计算的taken
     
     
     
    更新,更多方式:
    第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
    第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
    “URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。
     
    document.domain+iframe的设置
    针对主域名和子域名沟通
    在a.com上:
    document.domain = 'a.com';
    var ifr = document.createElement('iframe');
    ifr.src = 'http://script.a.com/b.html';
    ifr.style.display = 'none';
    document.body.appendChild(ifr);
    ifr.onload = function(){
        var doc = ifr.contentDocument || ifr.contentWindow.document;
        // 在这里操纵b.html
        alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
    };
     
    在child.a.com上:
    document.domain = 'a.com';
     
    注意一旦设置了document.domain以后就不能改回去,会导致错误,ie8开始就有这个限制
     
    window.name实现的跨域数据传输
    在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
    数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:
    <script type="text/javascript">
        window.name = 'I was there!';    // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
                                         // 数据格式可以自定义,如json、字符串
    </script>
    在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(和app同一域下,a.com/proxy.html)。app.html部分代码如下:
    <script type="text/javascript">
        var state = 0, 
        iframe = document.createElement('iframe'),
        loadfn = function() {
            if (state === 1) {
                var data = iframe.contentWindow.name;    // 读取数据
                alert(data);    //弹出'I was there!'
            } else if (state === 0) {
                state = 1;
                iframe.contentWindow.location = "http://a.com/proxy.html";    // 设置的代理文件
            }  
        };
        iframe.src = 'http://b.com/data.html';
        if (iframe.attachEvent) {
            iframe.attachEvent('onload', loadfn);
        } else {
            iframe.onload  = loadfn;
        }
        document.body.appendChild(iframe);
    </script>
    获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)。
    <script type="text/javascript">
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    </script>
    总结起来即:iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。
     
     
  • 相关阅读:
    第九周作业
    第八周
    第七周
    Jmeter连接到Mysql
    数据库常用链接URL写法
    功能测试方法
    常建输入框的测试
    系统业务流程测试(转)
    Linux
    搭建Git服务器
  • 原文地址:https://www.cnblogs.com/chuangweili/p/5166335.html
Copyright © 2011-2022 走看看