浏览器的跨域问题&跨域问题有哪些解决方法& JSONP 是如何实现跨域的?

1,042 阅读3分钟

浏览器跨域问题

1、什么是浏览器同源策略?

同源策略是一个重要的安全策略,它用于限制一个 origin 的文档或者它加载的脚本如何能与另一个源的资源进行交互,它能帮助阻隔恶意文档,减少可能被攻击的媒介。

所谓同源策略,是指只有在地址的:

  1. 协议名
  2. 域名
  3. 端口名

均一样的情况下,才允许访问相同的 cookielocalStorage,以及访问页面的 DOM 或是发送 Ajax 请求。

2、没有同源策略限制有哪些危险场景?

  • ajxa 请求
  • Dom 的查询 同源策略确实能规避一些危险,不是说有了同源策略就安全,只是说同源策略是一种浏览器最基本的安全机制,毕竟能提高一点攻击的成本。

3、为什么浏览器会禁止跨域?

  • 跨域只存在浏览器端,因为浏览器的形态很开放,需要对它进行限制。
  • 同源策略用于保护用户信息安全,防止恶意窃取数据(ajax 同源策略、Dom 同源策略)。

4、跨域有哪些解决方式?

CSDN 跨域问题解决

  1. jsonp
  2. cors
  3. postMessage
  4. websocket
  5. Node 中间件代理(两次跨域)
  6. nginx 反向代理
  7. window.name + iframe
  8. location.hash + iframe
  9. document.domain + iframe

5、CORS 常用的配置有哪些?

  • Access-Control-Allow-Origin 允许的域名
  • Access-Control-Allow-Methods 允许的 http 请求方法
  • Access-Control-Allow-Headers 支持的请求头
  • Access-Control-Allow-Credentials 是否发送 cookie
  • Access-Control-Max-Age 以秒为单位的缓存时间

6、CORS 跨域的判定流程

  1. 浏览器先判断是否同源,若同源,直接发送数据,否则,发送跨域请求;
  2. 服务器收到跨域请求后,根据自身配置返回对应的文件头;
  3. 浏览器根据收到的响应头里的 Access-Control-Allow-origin 字段进行匹配,若无该字段说明不允许跨域,报错,有该字段进行比对,判断是否可以跨域。

7、什么是简单请求?

简单请求是指满足以下条件的:

  • 使用 getposthead 其中一种方法进行请求的;
  • http 的头信息不超出一下情况:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID Content-Type:值仅限于 application/x-www-form-urlencodedmultipart/form-datatext/plain
  • 请求中 XMLHttpRequestUpload 对象没有注册任何的事件监听器;
  • XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。 请求中没有使用 ReadableStream 对象。

8、非简单请求

对服务器有特殊要求的请求(简单请求之外就是非简单请求)。

例如:请求方式是 putdeleteContent-Type 的类型是 application/json

非简单请求会在正式通信前使用 options 发起一个预检请求,询问服务器当前的域名是否在服务器允许的名单之中,以及使用哪些头信息字段等。

9、有哪些方法可一嵌入跨源的资源?

  • script 标签,嵌入跨域脚本;
  • link 标签,嵌入 css
  • img 标签,嵌入图片;
  • video/audio 标签,嵌入视频、音频;
  • object/embed/applet 标签,嵌入 svg /图片 等;
  • svg 标签,嵌入 svg
  • 通过 @font-face 嵌入字体;
  • 通过 iframe 嵌入资源

10、手动实现一个 JSONP

//Promise封装
function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    // 创建 script 标签
    let script = document.createElement('script')
    // 把 callback 挂载在 window 上,执行之后删除 script 
    window[callback] = function(data) {
      resolve(data)
      document.body.removeChild(script)
    }
    // 添加参数
    params = { ...params, callback } // wd=b&callback=callFun
    let arrs = []
    for (let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    // 设置 script 的 URL
    script.src = `${url}?${arrs.join('&')}`
    // 插入 body 中
    document.body.appendChild(script)
  })
}
// 调用示例
jsonp({
  url: 'http://localhost:3000/code',
  params: { wd: 'hello world' },
  callback: 'callFun'
}).then(data => {
  console.log(data) // 你好啊
  //再此回调结束后删除该script
})