同源策略

同一协议同一域名同一端口
以上有一项不满足,浏览器就会出现 No ‘Access-Control-Allow-Origin’ header is present on the requested resource

为什么浏览器不支持跨域

cookie localStorage
Dom元素也有同源策略 iframe
ajax也不支持跨域
http是无状态,区分不了是谁发送的请求,因此网站给你发个cookie做个标志,如果么有同源策略,则可能会向恶意的网站发送请求,拿到你的密码等重要信息。。。。

实现跨域

jsonp

  1. //后端部分
  2. const http = require('http');
  3. const express = require('express')
  4. let app = express()
  5. app.get('/say', function (req, res) {
  6. let { wd, cb } = req.query
  7. console.log(wd)
  8. res.end(`${cb}('好的')`)
  9. })
  10. app.listen(9000)
  1. // 客户端部分
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  8. <title>Document</title>
  9. </head>
  10. <body></body>
  11. <script>
  12. // 2 后端 callbackName(数据)
  13. function onResponse(posts) {
  14. console.log(posts);
  15. }
  16. function show(data) {
  17. console.log("执行show", data);
  18. }
  19. function jsonp({ url, params, cb }) {
  20. return new Promise((resovle, reject) => {
  21. window[cb] = function (data) {
  22. resovle(data);
  23. document.body.removeChild(script);
  24. };
  25. let arrs = [];
  26. let script = document.createElement("script");
  27. params = { ...params, cb };
  28. console.log(params);
  29. for (const key in params) {
  30. arrs.push(`${key}=${params[key]}`);
  31. }
  32. console.log(params);
  33. script.src = `${url}?${arrs.join("&")}`;
  34. document.body.appendChild(script);
  35. });
  36. }
  37. jsonp({
  38. url: "http://localhost:9000/say",
  39. params: { wd: "我爱中国" },
  40. cb: "show",
  41. }).then((data) => {
  42. console.log(data);
  43. });
  44. </script>
  45. <!-- <script src="http://localhost:9090/api"></script> -->
  46. </html>

jsonp的执行流程其实就是简单的两步。

  • 第一,在前端预先定义好一个带参数的回调函数用来接收后端传来的数据。
  • 第二,在后端启动一个server服务,将要传的数据以定义好了的回调函数名加上返回结果的方式传给前端
  1. 优点
    1. 它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制
    2. 它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
    3. 并且在请求完毕后可以通过调用callback的方式回传结果
  2. 缺点
    1. 只支持GET请求而不支持POST、put、delete等其它类型的HTTP请求
    2. 不安全 xss攻击,不采用
    3. 它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题

      cors

      纯后端解决跨域,最常用的解决方式
      首先制造跨域,9000端口访问9090端口的数据
      服务端部分 ```javascript // server1.js

const express = require(‘express’) let app = express() app.use(express.static(__dirname)) // localhost:9000 跑index.html文件 app.listen(9000)

// server2.js const express = require(‘express’) let app = express() app.get(‘/getData’, function (req, res) { res.end(‘我是另一个域的数据哈哈哈哈’) }) app.listen(9090)

  1. 客户端部分index.html
  2. ```javascript
  3. <!DOCTYPE html>
  4. <html lang="en">
  5. <head>
  6. <meta charset="UTF-8" />
  7. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  8. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  9. <title>Document</title>
  10. </head>
  11. <body>
  12. liang
  13. </body>
  14. <script>
  15. let xhr = new XMLHttpRequest();
  16. xhr.open("GET", "http://localhost:9090/getData", true);
  17. xhr.onreadystatechange = function () {
  18. if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
  19. console.log(xhr.response);
  20. }
  21. };
  22. xhr.send();
  23. </script>
  24. </html>
  25. // 数据是可以发送到服务器,只是服务器返回的结果被浏览器屏蔽了

访问http://localhost:9000/
image.png
image.png
解决 :设置请求源

  1. const express = require('express')
  2. let app = express()
  3. let whiteList = ['http://localhost:9000'] // 可以访问源,白名单
  4. app.use(function (req, res, next) {
  5. let origin = req.headers.origin
  6. if (whiteList.includes(origin)) {
  7. res.setHeader('Access-Control-Allow-Origin', origin)//* 代表接受任何源
  8. }
  9. next()
  10. })
  11. app.get('/getData', function (req, res) {
  12. res.end('我是另一个域的数据哈哈哈哈')
  13. })
  14. app.listen(9090)

image.png

postMessage

a页面中嵌入b页面,并给b页面发送数据‘hello 我是a’;
b页面收到a发来的数据;给a回复

  1. // a.html
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8" />
  6. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  7. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  8. <title>Document</title>
  9. </head>
  10. <body>
  11. <iframe
  12. src="http://localhost:4000/b.html"
  13. frameborder="0"
  14. id="frame"
  15. onload="load()"
  16. ></iframe>
  17. </body>
  18. <script>
  19. function load() {
  20. let frame = document.getElementById("frame");
  21. // 发送hello 我是a给b页面
  22. frame.contentWindow.postMessage("hello 我是a", "http://localhost:4000");
  23. window.onmessage = function (e) {
  24. console.log(e.data);
  25. };
  26. }
  27. </script>
  28. </html>
  29. // b.html
  30. <!DOCTYPE html>
  31. <html lang="en">
  32. <head>
  33. <meta charset="UTF-8" />
  34. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  35. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  36. <title>Document</title>
  37. </head>
  38. <body>
  39. b
  40. </body>
  41. <script>
  42. window.onmessage = function (e) {
  43. console.log("b接收到的", e.data);
  44. e.source.postMessage("我给a答复:你好,我是b", e.origin);
  45. };
  46. </script>
  47. </html>
  1. // a.js
  2. //后端部分
  3. const express = require('express')
  4. let app = express()
  5. app.use(express.static(__dirname)) // localhost:9000 跑index.html文件
  6. app.listen(3000)
  7. // b.js
  8. //后端部分
  9. const express = require('express')
  10. let app = express()
  11. app.use(express.static(__dirname)) // localhost:9000 跑index.html文件
  12. app.listen(4000)

访问http://localhost:3000/a.html
image.png

document.domain

window.name

拿到跳转页面的window.name的值
c.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. 我是C
  11. </body>
  12. <script>
  13. window.name = "我的name是liangchunjian";
  14. </script>
  15. </html>

a.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <iframe
  11. src="http://localhost:4000/c.html"
  12. frameborder="0"
  13. id="frame"
  14. onload="load()"
  15. ></iframe>
  16. </body>
  17. <script>
  18. // a,b同域
  19. // c独立
  20. // a获取c的数据
  21. // a先引用c,c把数据放在window.name
  22. let first = true;
  23. function load() {
  24. let frame = document.getElementById("frame");
  25. if (first) {
  26. frame.src = "http://localhost:3000/b.html";// 切换到b
  27. first = false;
  28. } else {
  29. console.log(frame.contentWindow.name); // 拿到通过name拿到c中的数据
  30. }
  31. }
  32. </script>
  33. </html>

image.png

location.hash

http-proxy

nginx

websocket