js 跨域(JSONP/CORS/WebSocket/postMessage/location.hash/document.domain/window.name)

目录

前言

一、跨域

1、跨域的产生

二、解决跨域

1、具备src的标签

2、JSONP

3、CORS

4、WebSocket 协议(★★★★★)

(1)、WebSocket 协议的特点

(2)、WebSocket 协议客户端的 API

5、postMessage(★★★★★)

6、location.hash

7、document.domain

8、window.name

三、其他

1、反向代理

2、只针对Chrome的跨域解决办法

(1)、windows 操作系统

(2)、MAC OS 操作系统

四、对跨域的进一步学习

五、特殊的跨域


前言

一篇优秀的文章:JavaScript学习总结(二)——延迟对象、跨域、模板引擎、弹出层、AJAX示例 - 张果 - 博客园

一、跨域

1、跨域的产生

同源策略:同协议、同域名、同端口。

同源策略限制以下几种行为:

  • Cookie、LocalStorage 和 IndexDB 无法读取。
  • DOM 和 Js对象无法获得。
  • AJAX 请求不能发送。

不遵守同源策略的通信就会产生跨域。

二、解决跨域

1、具备src的标签

原理:所有具有src属性的HTML标签都是可以跨域的

在浏览器中,

(2)、b.html:(http://www.domain2.com/b.html)


(3)、c.html:(http://www.domain1.com/c.html)

7、document.domain

此方案仅限主域相同,子域不同的跨域应用场景。

实现原理:两个页面都通过js强制设置document.domain为基础主域,就实现了同域。

(1)、父窗口:(http://www.domain.com/a.html)


(2)、子窗口:(http://child.domain.com/b.html)

8、window.name

window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。

(1)、a.html:(http://www.domain1.com/a.html)

var proxy = function(url, callback) {
    var state = 0;
    var iframe = document.createElement('iframe');

    // 加载跨域页面
    iframe.src = url;

    // onload事件会触发2次,第1次加载跨域页,并留存数据于window.name
    iframe.onload = function() {
        if (state === 1) {
            // 第2次onload(同域proxy页)成功后,读取同域window.name中数据
            callback(iframe.contentWindow.name);
            destoryFrame();

        } else if (state === 0) {
            // 第1次onload(跨域页)成功后,切换到同域代理页面
            iframe.contentWindow.location = 'http://www.domain1.com/proxy.html';
            state = 1;
        }
    };

    document.body.appendChild(iframe);

    // 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)
    function destoryFrame() {
        iframe.contentWindow.document.write('');
        iframe.contentWindow.close();
        document.body.removeChild(iframe);
    }
};

// 请求跨域b页面数据
proxy('http://www.domain2.com/b.html', function(data){
    alert(data);
});

(2)、proxy.html:(http://www.domain1.com/proxy....
中间代理页,与a.html同域,内容为空即可。

(3)、b.html:(http://www.domain2.com/b.html)

总结:通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

三、其他

1、反向代理

js 跨域(JSONP/CORS/WebSocket/postMessage/location.hash/document.domain/window.name)_第1张图片

反向代理的原理:受同源策略的限制,非同源的通信就会产生跨域,导致客户端直接与服务器通讯失败,于是另辟蹊径,可以在本地配置一个服务器(我自测采用的是Wampserver(PHP+Apache)),配置好反向代理后,直接访问本地服务器,本地服务器会去访问远程服务器,服务期间的通信没有跨域,所以就绕开了跨域,借助本地服务器成功返回了数据。

反向代理学习资源大全:js的反向代理 - 腾讯云开发者社区 - 腾讯云

  • 反向代理的概念:反向代理为什么叫“反向”代理? - 腾讯云开发者社区-腾讯云
  • Node.js 配置反向代理:使用 NodeJS 实现反向代理 - 腾讯云开发者社区-腾讯云
  • Nginx 配置反向代理:Nginx的反向代理与负载均衡 - 腾讯云开发者社区-腾讯云

2、只针对Chrome的跨域解决办法

允许Chrome读写一个特定的文件夹。

(1)、windows 操作系统

①、打开任务管理器,确保里面没有chrome 进程 

②、右键谷歌浏览器,"属性"中打开文件所在位置,进入浏览器安装文件夹

③、在文件位置栏中启动cmd命令行,输入chrome.exe,确定是否能启动浏览器。如果不能请检查自己浏览器文件的路径是否正确

④、 然后关掉chrome浏览器,通过在命令行输入chrome.exe --disable-web-security --user-data-dir 或 chrome.exe --args --disable-web-security --user-data-dir。

⑤、将指令“ --disable-web-security --user-data-dir” 或 “ --args --disable-web-security --user-data-dir”粘贴到这条下图的目标中,注意有空格,这两种方式都是一样的,直接粘贴这种其实就相当于系统打开谷歌时执行了“目标”里的指令而已。

js 跨域(JSONP/CORS/WebSocket/postMessage/location.hash/document.domain/window.name)_第2张图片

(2)、MAC OS 操作系统

1⃣️、允许Chrome读写一个文件夹,比如:CCD。

新建一个文件夹,作为允许chrome读写的文件夹,查看其路径。

在terminal里运行以下命令:

open -n /Applications/Google\ Chrome.app/ --args --disable-web-security  --user-data-dir=刚刚新建的文件夹的路径(我的是/Users/CCD)

命令执行后,弹出窗口,提示如下图:

js 跨域(JSONP/CORS/WebSocket/postMessage/location.hash/document.domain/window.name)_第3张图片

点击启动即可开启一个新的网页,该网页已经可以读写CCD文件夹了。

2⃣️、解决302报错

再运行项目,可能会报错302(资源被重定向找不到了),怎么办呢?

在浏览器地址栏输入并访问下面的网址:

// chrome 浏览器的某些实验功能
chrome://flags/

ctrl+F 搜索:same-site-by-default-cookies,并将其设置为 disabled(禁用)。

最后别忘了点击 relaunch哦。

四、对跨域的进一步学习

请戳此链接:https://segmentfault.com/a/1190000011145364

五、特殊的跨域

首先抛出一个问题:在本地访问本机起的服务会产生跨域吗?

答案是会的。下面我就来还原一下这个问题。

比如:我的 IP 地址是 192.168.x.x,我的端口号是 8080,起的服务的端口号是 8181

目标接口是:http://192.168.x.x:8080/getData

我前端页面访问的 URL 是:http://192.168.x.x:8080/home

所以,我做了代理(本案例用的是 vue2):

module.exports = defineConfig({
    DevServer: {
        port: 8080,
		hot: true,
		proxy: {
			'/api': {
				target: "http://192.168.x.x:8181",
				ws: false,
				changeOrigin: true,
				pathRewrite: {
					'^/api': '' 
				}
			}
		}
    }
})

代理后,我要访问的接口会变为:http://192.168.x.x:8181/api/getData

这样做是正确的,没问题。但是,如果我前端页面访问的 URL 改为:http://localhost:8080/home,会发生什么?产生跨域了。至此,问题还原了。这是为什么呢?

这是因为 localhost 与 192.168.x.x 是不同的,localhost 不会被 DNS 解析为本机 IP 地址,那么显然这违反了 “同源策略” 的 “同域名” 的原则了,所以就会产生跨域了。

你可能感兴趣的:(JavaScript,javascript,websocket,哈希算法)