同源策略

在控制台输入 window.origin

源=协议+域名+端口

协议 +域名+端口号 完全一致 才是同源

浏览器不允许跨域

同源策略是限制的数据访问,我们并看不见里面的数据。

能引用这个js 但是不能读取里面的数据

举例(省略http协议)

假设frank.com/index.html引用了cdn.com/1.js

那么就说{1.js运行在源frank.com里 }

注意这跟cdn.com没有关系,虽然1.js从它那下载

所以1.js就只能获取frank.com的数据

不能获取1.frank.com或者qq.com的数据

目的

为了保护用户隐私

举个例子:

假设有一个kang.com 网站和qq.com网站文件夹状况如下

20 跨域 - 图1

在没有使用跨域的状态下,如果kang.com 想使用 qq.com里面的friends.json 。是无法那到里面的相关数据。

会报如下错误

20 跨域 - 图2

这里的请求是发成功了的,但是没有拿到数据

实现跨域

CORS

在server.js里面添加

  1. response.setHeader("Access-Control-Allow-Origin", "允许的网址")

代码展示:

  1. if(path === "/friends.json") {
  2. response.statusCode = 200
  3. // 允许跨域访问
  4. response.setHeader("Access-Control-Allow-Origin", "http://kang.com:9999")
  5. response.setHeader("Content-Type", "text/json;charset=utf-8")
  6. response.write(fs.readFileSync("./public/friends.json"))
  7. response.end()
  8. }

jsonp

我们在跨域的时候由于当前浏览器不支持CORS,我们必须使用另一种方式来跨域

于是我们就请求一个js文件,js文件会执行一个回调,回调里面就有个数据。

回调里面的名字可以随机生成的,一个随机数,这个名字再以callback的参数传给后台

后台会吧函数再次返回给我们并执行。

优点

  • 兼容IE
  • 可以跨域

缺点

  • 由于它是script标签 不能像AJAX读取到状态码和请求头,只知道成功和失败,
  • 由于它是script标签 只能发GET请求,不支持POST。

代码展示:

  1. // 服务器里面的代码
  2. if (path === "/friends.js") {
  3. if (request.headers["referer"].indexOf("http://kang.com:9999") === 0) {
  4. response.statusCode = 200
  5. response.setHeader("Content-Type", "text/javascript;charset=utf-8")
  6. const string = "window['{{xxx}}']({{data}})"
  7. const data = fs.readFileSync("./public/friends.json").toString()
  8. const string2 = string
  9. .replace("{{data}}", data)
  10. .replace("{{xxx}}", query.callback)
  11. response.write(string2)
  12. response.end()
  13. } else {
  14. request.statusCode = 404
  15. response.end()
  16. }
  17. }
  1. // jsonp 代码 封装后的
  2. function jsonp(url) {
  3. return new Promise((resolve, reject) => {
  4. const random = "kangJSONPCallbackName" + Math.random()
  5. window[random] = (data) => {
  6. console.log(data)
  7. }
  8. // 创建script标签并引用链接
  9. const script = document.createElement("script")
  10. script.src = `${url}?callback=${random}`
  11. // 加载完后就删除script标签
  12. script.onload = () => {
  13. script.remove()
  14. }
  15. script.onerror = () => {
  16. reject()
  17. }
  18. // 将script插入body里面
  19. document.body.appendChild(script)
  20. })
  21. }
  22. // 输入可以跨域的地址
  23. jsonp("http://qq.com:8888/friends.js").then((data) => {
  24. console.log(data)
  25. })

其他疑问

为什么a.qq.com访问qq.com也算跨域?

答:因为历史上,出现过不同公司共用域名,a.qq.com和qq.com不一定是同一个网站,浏览器谨慎起见,认为这是不同的源

为什么不同端口也算跨域?

答:原因同上,一个端口一个公司。记住安全链条的强度取决于最弱一环,任何安全相关的问题都要谨慎对待

为什么两个网站的IP是一样的,也算跨域?

答:原因同.上,IP可以共用。
为什么可以跨域使用CSS、JS和图片等?

答:同源策略限制的是数据访问,我们引用CSS、JS和图片的时候,其实并不知道其内容,我们只是在引用。