Skip to content

跨源(跨域)

定义

翻译问题,实际是跨源 origin = protocol + domain + port

出于安全原因,浏览器限制从脚本内发起的跨源 HTTP 请求。 例如,XMLHttpRequest 和 Fetch API 遵循同源策略。 这意味着使用 这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非使用 CORS 头文件。

  1. 服务端设置允许:Access-Control-Allow-Origin
  2. jsonp 伪跨域,需要服务端配合
  3. 利用 Apache 转发 如何解决 Ajax 跨域请求不到的问题? - pig pig 的回答 - 知乎 同源策略和跨域访问 - lg2045 的个人空间 - 开源中国社区
  4. gulp 代理插件 gulp-connect-proxy 浅谈 WEB 跨域的实现(前端向) - vajoy - 博客园 Javascript 跨域访问解决方案 - 老唐 的专栏 - 博客频道 - CSDN.NET ajax 跨域问题解决方案 | w3cboy,最专业的前端开发博客

浏览器拦截只是页面拿不到数据,请求是正常收发的

分类

请求跨域 Client-Server

- jsonp
- cors

页面跨域 Page-Page

- postMessage
- document.domain(不推荐,标准已移除)

JSONP

由于同源策略的限制,XmlHttpRequest只允许请求当前源,script标签没有同源限制

但是现在浏览器,默认会检查 MIME-type,如 script 请求 json 会被 CORB 拦截

js
import jsonp from 'jsonp-es6'

axios/COOKBOOK.md at master · mzabriskie/axiosjsonp跨域资源引起CORB_记忆阁楼 - SegmentFault 思否Fetch Standard CORB

jsonp 数据结构

jsonpcallback({
  "id": 1,
  "room": "main bedroom",
  "items": [ "bed", "chest of drawers" ]
});

服务端代码,返回的是一个函数调用,数据作为参数

java
    //用回调函数名称包裹返回数据
    String result = callback + "(" + jsonData + ")";
    response.getWriter().write(result);

客户端代码,请求文件 MIME type 应该是 javascript

js
function requestJSONP(url) {
  // create script with passed in URL
  var script = document.createElement('script');
  script.src = url;
  script.async = true;
  
  // after the script is loaded (and executed), remove it
  script.onload = function () {
    this.remove();
  };
  
  // insert script tag into the DOM (append to <head>)
  var head = document.getElementsByTagName('head')[0];
  head.appendChild(script);
}

var url = "https://api.map.baidu.com/place/v2/search?query=ATM机&tag=银行&region=北京&output=json&ak=F552bedbee2ec8fa6bae7b7a08201&callback=callback";

requestJSONP(url)

var callback = function (data) {
  var json = JSON.stringify(data);
  console.log(json);
};

CORS

服务器通过设置 Access-Control-Allow-Origin 来指定接受哪些域(以下仅用于跨域情况)

  • 需要服务器设置支持

  • Access-Control-Allow-Origin 有两种情况,一个精确域名或*

    如何配置多个,写多条?缓存允许多个访问需要设置vary

  • Access-Control-Allow-Credentials 表示是否允许发送 cookie,只能是 true,不需要就不要写

  • Access-Control-Allow-Credentials 读取跨域响应内容限制,客、服均需设置

  • cookie 比较敏感,需要两端配合,才能传送,且只能同源,域名要求至少有两个点,localhost 不符合

  • 不管是否为跨域请求,ORIGIN 字段总是被发送

  • Chrome/Firefox 不允许 https 向 http 发跨域请求,会被拦截

绕过浏览器 SOP,跨站窃取信息:CORS 配置安全漏洞报告及最佳部署实践 | Jianjun Chen's Homepage

javascript - Http requests withCredentials what is this and why using it? - Stack Overflow

axios 的 cookie 跨域以及相关配置 - 个人文章 - SegmentFault 思否

http - Set-Cookie header has no effect - Stack Overflow

ajax 如何带上 cookie - DCloud 问答

webpack-dev-server 代理解决 cookie 丢失问题 - 掘金

postMessage

发散:页面通信还有哪些方法

  • storage event 作用于 localStorage/sessionStorage 共享的页面

    js
    let o = window.open('http://baidu.com')
    o.focus()

    即使同源,并不能访问或修改 window 下的大部分变量

开发模式代理设置

  • create-react-app可在 package.json 中设置proxy: "http://localhost:8080",要配合 fetch/ajax 使用
  • vue-cli创建的可在config.js/index.js中设置
  • 要代理跨域请求,请求必须指向代理地址(localhost)才 work
js
dev: {
  // ...
  proxyTable: {
    '/api': {
      target: 'http://localhost:8081',
      // changeOrigin: true // 不是必须?
      pathRewrite: {
        '^/api': '' // 重写接口
      }
    },
    // http://example.com/result/xxxx.mp4
    '/result': {
      target: 'http://example.com',
    }
  },

devServer: {
  ...
  headers: {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
    "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
  }
}

Vue-cli proxyTable 解决开发环境的跨域问题 - 简书JS 中关于跨域及实现方法 | plainnany使用 vue-axios 和 vue-resource 解决 vue 中调用网易云接口跨域的问题 - 个人文章 - SegmentFault前端跨域问题及解决方案 · Issue #2 · wengjq/Blog由同源策略到前端跨域 | louis blog

Same-origin policy - Web security | MDN

How to win at CORS - JakeArchibald.com