如何实现跨域

81 阅读4分钟

三种比较主流的跨域方案

最经典的跨域方案jsonp

jsonp本质上是一个Hack,它利用

function JSONP({ 
   url,
   params, 
   callbackKey, 
   callback
}) {
  // 在参数里制定 callback 的名字
  params = params || {} 
  params[callbackKey] = 'jsonpCallback'
  // 预留 callback 
  window.jsonpCallback = callback
  // 拼接参数字符串
  const paramKeys = Object.keys(params) 
  const paramString = paramKeys
  .map(key => `${key}=${params[key]}`) .join('&')
  // 插入 DOM 元素
  const script = document.createElement('script') 
  script.setAttribute('src', `${url}?${paramString}`)   
  document.body.appendChild(script)
}
JSONP({
  url: 'http://s.weibo.com/ajax/jsonp/suggestion', 
  params: {
   key: 'test',
  },
  callbackKey: '_cb', callback(result) {
  console.log(result.data) }
})
                  

最流行的跨域方案cors

cors是目前主流的跨域解决方案,跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一 个 origin (domain) 上的Web应用被准许访 问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同 的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求

如果你用express,可以这样在后端设置

  //CORS middleware
  var allowCrossDomain = function(req, res, next) { 
    res.header('Access-Control-Allow-Origin', 'http://example.com'); 
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); 
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    next(); 
  }
  //...
  app.configure(function() { 
  app.use(express.bodyParser());  
  app.use(express.cookieParser());
  app.use(express.session({ secret: 'cool beans' })); 
  app.use(express.methodOverride()); 
  app.use(allowCrossDomain);
  app.use(app.router);
  app.use(express.static(__dirname + '/public')); });
             

在生产环境中建议用成熟的开源中间件解决问题。

最方便的跨域方案Nginx

nginx是一款极其强大的web服务器,其优点就是轻量级、启动快、高并发。 现在的新项目中nginx几乎是首选,我们用node或者java开发的服务通常都 需要经过nginx的反向代理。

反向代理的原理很简单,即所有客户端的请求都必须先经过nginx的处理, nginx作为代理服务器再讲请求转发给node或者java服务,这样就规避了同源策略

  #进程, 可更具cpu数量调整 
  worker_processes 1;
  
  events { #连接数
    worker_connections 1024;
  }
  
  http {
      include mime.types;
      default_type application/octet-stream;
      
      sendfile on;
      #连接超时时间,服务器会在这个时间过后关闭连接。 
      keepalive_timeout 10;
      # gizp压缩 
       gzip on;
      # 直接请求nginx也是会报跨域错误的这里设置允许跨域
      # 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)  
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Allow-Headers X-Requested-With; 
      add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
      # srever模块配置是http模块中的一个子模块,用来定义一个虚拟访问主机
      server {
       listen 80; server_name localhost;
      # 根路径指到index.html 
      location / {
        root html;
      index index.html index.htm;
     }	
     
     # localhost/api 的请求会被转发到192.168.0.103:8080
     location /api {
      rewrite ^/b/(.*)$ /$1 break; # 去除本地接口/api前缀, 否则会出现404
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_pass http://192.168.0.103:8080; # 转发地址
      }
      # 重定向错误⻚面到/50x.html
      error_page 500 502 503 504 /50x.html; 
      location = /50x.html {
         root html; 
      }
  } }

其它跨域方案

  1. HTML5 XMLHttpRequest 有一个APIpostMessage()方法允许来自不
 同源的脚本采用异步方式进行有限的通信, 可以实现跨文本档、多窗口、跨域消息传递。
  2. WebSocket 是一种双向通信协议,在建立连接之后,WebSocketserverclient 都能主动向对方发送或接收数 据,连接建立好了之后 clientserver 之间的双向通信就与 HTTP 无关了,因此可以跨域。
  3. window.name + iframe:window.name属性值在不同的⻚面(甚至不同域名)
  加载后依旧存在,并且可以支持非常 ⻓的 name 值,我们可以利用这个特点进行跨域。
  4. location.hash + iframe:a.html欲与c.html跨域相互通信,通过中间⻚
  b.html来实现。 三个⻚面,不同域之间利用 iframelocation.hash传值,相
  同域之间直接js访问来通信。
  5. document.domain + iframe: 该方式只能用于二级域名相同的情况下,比如 
  a.test.comb.test.com 适用于该方 式,我们只需要给⻚面添加 
  document.domain ='test.com' 表示二级域名都相同就可以实现跨域,两个
  ⻚面都通过js 强制设置document.domain为基础主域,就实现了同域。