Javascript跨域总结

本文介绍了JavaScript跨域问题产生的原因——同源策略,并详细阐述了解决跨域的几种方式,包括JSONP、AJAX、SSE(服务器发送事件)和WebSocket。分别展示了它们的工作原理和使用示例,帮助读者理解和掌握不同场景下的跨域解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是跨域?

我们经常会在页面上使用ajax请求访问其他服务器的数据,此时,客户端会出现跨域问题,跨域问题是由于javascript语言安全限制中的同源策略造成的。简单来说,同源策略是指一段脚本只能读取来自同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合。例如:

这里写图片描述

解决跨域的几种方式:

JSONP

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。其核心思想是利用JS标签里面的跨域特性进行跨域数据访问,在JS标签里面存在的是一个跨域的URL,实际执行的时候通过这个URL获得一段字符串,这段返回的字符串必须是一个合法的JS调用,通过EVAL这个字符串来完成对获得的数据的处理。
在HTML文档中能够发起HTTP请求的元素有:< a>,< img >,< link> ,< script>,< iframe>< frame>请求HTML文档文件,< form>请求(get/post),< object>请求其他资源文件,音频视频,插件,< source>用于音频视频,从域的概念来讲,HTML中的这些元素,都是可以跨域请求资源的。这些请求都是传统的HTTP请求。
代码:
服务器端:Nodejs服务器

var http = require("http");
var https = require("https");
url = require('url');
var port = process.env.PORT || 9000;
function requestlistener(req, res) {
    res.writeHead(200,{"Content-Type":"application/json"});
    var otherArray = ["item1", "item2"];
    var otherObject = { item1: "item1val", item2: "item2val" };
    var json = JSON.stringify({
        anObject: otherObject,
        anArray: otherArray
    });
    req = url.parse(req.url, true);
    if(!req.query.callback){
        res.end();
    }
    //console.log("name is:"+req.query.name);
    res.write(req.query.callback+"("+json+")");
    res.end();
}
http.createServer(requestlistener).listen(port);
console.log('The HTTPS server is listening on port ' + port);

客户端:分2种形式jquery.getJSON和jquery.ajax
getJSON:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>crossDomain</title>
    <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js" type="text/javascript"></script>
</head>
<body>
<div>
    <button onclick="getjson()">click me!</button>
    <p>...</p>
</div>
<script type="text/javascript">
function getjson() {
    $.getJSON("http://60.205.226.32:9000/?callback=?", function(result){
        console.log(result);
    });
}
</script>
</body>
</html>

ajax:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>crossDomain</title>
    <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js" type="text/javascript"></script>
</head>
<body>
<div>
    <button>click me!</button>
    <p>...</p>
</div>
    <script type="text/javascript">
        const hostname = '60.205.226.32';
        const port = 9000;
        function getJSon(data) {
            $("p").html(JSON.stringify(data));
            //document.getElementById("ppp").innerHTML=(JSON.stringify(data));
            console.log(data);
        }
    $(function(){
            $("button").bind("click",function(){
                    var url = "http://" + hostname + ":" + port;
                    $.ajax({
                            url:url,
                            crossDomain:true,
                            dataType:"jsonp",
                            jsonp:"callback",
                            jsonpCallback:"getJSon"
                    })
                });
        });
    </script>
</body>
</html>

这两种方法,点击button的时候,从Firefox浏览器的firebug,实际上都在head里面能看到动态生成了一段script 里面有服务器的src,其实, JSONP就是利用script 的 src属性,实现跨域的功能.

AJAX:

相信这个应该不用过多的讲解了吧.
差不多就4步:
•创建xhr对象
•监听请求
•设置回调
•设置参数
•发送xhr
•获得数据执行回调
这里,我就直接上代码了.

var sendAjax = (function() {
    var getXHR = (function() {
        var xhr;
        if(window.XHRHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveObject("Microsoft.XMLHTTP");
        }
        return xhr;
    })();
    return function(url,opts){ //url为目标地址
        var xhr = getXHR(),
        data;
        xhr.onreadystatechange = function(){
            if(xhr.readyState===4||xhr.status===200){
                data = JSON.parse(xhr.responseText);  //将data解析为json对象
                opts.callback(data);
            }
        }
        xhr.setRequestHeader('Content-Type','application/json');
        xhr.open(opts.method,url);  //写入参数
        xhr.send(JSON.stringify(opts.data));  //将参数json字符化
    }
})();
//调用执行
sendAjax('www.example.com',{
    callback:function(data){
        //...
    },
    data:{
        name:'JIMMY',
        age:18
    }
})

JSONP 就是 JSON with Padding… 我真的不知道这个名字的含义到时有什么卵用
一开始在使用JSONP时, 就是使用jquery的$.ajax函数就可以了. 但,这造成了一个很不好的impression. 总是让我们以为,JSONP 和 ajax有什么关联似的. 而,事实上,他们两个是完全不同的机制。

SSE:

ajax和JSONP 都是 client-fetch的操作. 但是有时候, 我们更需要服务器主动给我们发信息. 比如,现在的APP应用,完全可以实现服务器发送, 然后Client再处理. 而,SSE就是帮助我们向webapp靠近.
SSE 全称就是 Server-Sent Events. 中译 为 服务器推送.
他的技术并不是很难,和websocket不同,他依赖原生的HTTP,所以对于开发者来说更好理解。 比如,在nodeJS, 只要我不执行res.end(),并且一定时间持续发送信息的话,那么该连接就会持续打开(keep-alive). 其实通俗来说,就是一个长连接. 所以,以前我们通常使用ajax,iframe长轮询来代替他.但是这样有个缺点就是, 可操控性弱, 错误率高。 所以,正对于这点W3C, 觉得需要在客户端另外指定一个机制–能够保证服务器推送, 实现连接的keep-alive,操作简单… 在这样背景下SSE诞生了.
但SSE和AJAX具体的区别在什么地方呢?
•数据类型不同: SSE 只能接受 type/event-stream 类型. AJAX 可以接受任意类型
•结束机制不同: 虽然使用AJAX长轮询也可以实现这样的效果, 但是, 服务器端(nodeJS)必须在一定时间内执行res.end()才行. 而SSE, 只需要执行res.write() 即可.
简单demo:

var source = new EventSource('/dates');  //指定路由发送
source.onmessage = function(e) {  //监听信息的传输
    var data = JSON.parse(e.data),
        origin = e.origin;
};
source.onerror = function(e) { //当连接发生error时触发
    console.log(e);
};
source.onopen = function(e) { //当连接正式建立时触发
    console.log(e);
};

SSE主要就是创建一个EventSource对象. 里面的参数就是发送的路由, 不过目前还不支持CORS,所以也被限制在同源策略下.
在返回的source里面包含了,需要处理的一切信息.SSE也是通过事件驱动的,如上面demo所述. 这里,SSE通常有一下几类重要的事件.
这里写图片描述
上面几个方法比较重要的还是message方法. message主要用来进行信息的接受, 回调中的event 包含了返回的相关数据.
event包含的内容:
这里写图片描述
服务端使用SSE:
由于使用的是HTTP协议,所以对于服务端基本上没什么太大的改变. 唯一注意的就是, 发送数据使用res.write()即可,断开的时候使用res.end();

res.writeHead(200, {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      "Access-Control-Allow-Origin": "*" //允许跨域
    });
var num =0;
var f = function(){
   if(num===10){
      res.end();
   }else{
    res.write("id: " + num + "n");
    res.write("data: " + num + "nn");
    num++;
   }
   setTimeout(f,1000);
}
f();

Ok~ 这里有一个demo, 大家可以打开控制台看一下. 会发现,有一个连接一直处于Content-Download状态. 该连接就是一个SSE。

WebSocket:

websocket 不同于其他的HTTP协议,他是独立于HTTP存在的另外一种通信协议。比如,像这样的一个路径ws://websocket.example.com/,就是一个websocket 通信. 通常的实时通信并不会传输大量的内容, 所以,对于HTTP协议那种,进行连接时需要传递,cookie和request Headers来说, 这种方式的通信协议,会造成一定的时延(latency). websocket通信协议就是在这样的背景下诞生了, 他与SSE,ajax polling不同的是–双向通信。
我们来看一个简单的websocket demo:

var socket = new WebSocket('ws://localhost:8080/');
  socket.onopen = function () {
      console.log('Connected!');
  };
  socket.onmessage = function (event) {
      console.log('Received data: ' + event.data);
      socket.close();
  };
  socket.onclose = function () {
      console.log('Lost connection!');
  };
  socket.onerror = function () {
      console.log('Error!');
  };
  socket.send('hello, world!');

可以说上面就是一个健全的websocket 通信了. 和SSE一样,我们需要创建一个WebSocket对象, 里面的参数指定连接的路由. 而且,他也是事件驱动的.

常见的事件监听有.

websocket 发送数据:
另外,websocket 最大的特点就是可以双向通信。这里可以使用.
ws.send()方法发送数据, 不过只能发送String和二进制. 这里,我们通常call 数据叫做 Frames. 他是数据发送的最小单元.包含数据的长度和数据内容.

下面就是几种常用的发送方式:

socket.send("Hello server!"); 
socket.send(JSON.stringify({'msg': 'payload'})); 
  var buffer = new ArrayBuffer(128);
  socket.send(buffer); 
  var intview = new Uint32Array(buffer);
  socket.send(intview); 
  var blob = new Blob([buffer]);
  socket.send(blob);

websocket 接受数据:

ws.onmessage = function(msg) { 
  if(msg.data instanceof Blob) { 
    processBlob(msg.data);
  } else {
    processText(JSON.parse(msg.data)); //接受JSON数据
  }
}

那server端应该怎样处理websocket通信呢?
websocket虽然是另外一种协议,不过底层还是封装了TCP通信, 所以使用nodeJS的net模块,基本就可以满足,不过里面需要设置很多的头. 这里推荐使用ws模块.
NodeJS 发送websocket数据:

var WebSocketServer = require('ws').Server
  , wss = new WebSocketServer({ port: 8080 });
//通过ws+ssl的方式通信. 和HTTPS类似
wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });
  ws.send('something');
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值