跨域方法大全

190 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情

前言

说到跨域,可能所有前端都觉得这个知识很基础,都掌握了;那么今天就来聊一聊哪些一般人不知道的跨域知识;首先如何判定两个url是跨域的呢?只要协议、域名、端口有一个不同那么就算是跨域;一般后端的接口部署的服务器和前端的服务器都不一样,因此一般都会跨域,那么应该怎么处理这个问题呢?

jsonp

一开始我们先用暴力法解决这个问题,直接用jsonp进行跨域请求;

jsonp是利用动态添加script标签实现的,用script去发送跨域GET请求,一个必要的参数就是callback,下面我们先搭建一个node服务端:

const app = require('express')()
app.get("/api",function(req,res){
  var func  = req.query.callback
  res.send(`${func}({
    data:[],
    success:true
  })`)
})

然后前端我们动态创建一个script去发起这个jsonp请求:

function handleResponse(response){
    console.log(response.data,response.success)
}

var script = document.createElement(“script”);
script.src = “http://freegeoip.net/json/?callback=handleResponse”;
document.body.insertBefore(script, document.body.firstChild);

由于jsonp只能支持GET方法,所以除非万不得已我们一般不使用这种跨域方法解决接口的跨域问题

CORS

服务端可以设置允许跨域的域名:Access-Control-Allow-Origin: http://api.bob.com以此开启CORS请求,如果服务端没有返回这个字段那么请求直接会报错

CORS请求的响应Headers中会多几个字段:

  1. Access-Control-Allow-Origin:允许跨域的域名
  2. Access-Control-Allow-Credentials:请求是否携带Cookie,取值:Boolean;默认情况下,Cookie不包括在CORS请求之中;要发送cookie的话:Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名
  3. Access-Control-Expose-Headers:CORS暴露的Headers

如果是非简单请求则还会发送预检请求(OPTIONS请求),这个请求会发送两个额外的Header,主要是为了确保请求的安全性:

  1. Access-Control-Request-Method
  2. Access-Control-Request-Headers

总结一下:CORS请求存在Cookie不能跨域的问题,所以也不是最佳的选择

反向代理

什么是反向代理?就是给服务器做代理,跟它相反的是正向代理,一般是在客户端配置代理然后去访问服务端;

反向代理一般是用nginx,假设接口部署在http://127.0.0.1:8088,而我们的应用在http://127.0.0.1:8080,我们用http://127.0.0.1:8080/api/***去请求接口,然后配置一下nginx:

server{
  listen 8080;
  server_name localhost;

  location /api {
    proxy_pass  http://127.0.0.1:8088; # 转发规则
  }
}

反向代理是解决接口跨域的最好的办法,如何配置反向代理也是前端必须掌握的技能

iframe

iframe最早是用来实现微前端的,可以实现不同网站页面的切换,那么iframe如何跨域呢?

iframe不同窗口之间可以使用postMessage进行通信,当然他们也可以用postMessage进行跨域通信:我们可以本地开两个服务来进行验证,主应用端口号5500,子窗口端口号为1234

<iframe id='iframe' src='http://localhost:1234'></iframe>


window.onload = function () {
  window.addEventListener('message', function () {
    console.log('http://127.0.0.1:5500/ 接收到了跨域兄弟的来信!!')
  })

  window.postMessage('hello', 'http://localhost:1234')

  document.getElementById('iframe').contentWindow.postMessage('1', 'http://localhost:1234')
}

// 子窗口
window.addEventListener('message', function (data) {
  console.log('http://localhost:1234 接收到了跨域兄弟的来信!!', data)

  window.parent.postMessage(data.data + 'callback', 'http://127.0.0.1:5500/')
})

开发环境解决跨域

虽然在线上环境nginx是最好的方式,但是开发环境下不必费很大的力气去配置nginx来解决跨域,一般有以下几个方法:

  1. 关闭所有Chrome浏览器,执行open -a Google\ Chrome --args --disable-web-security --user-data-dir=/Users/zhuxiansheng/tools/chromeDevUserData打开非安全模式,这样所有请求都支持跨域

  2. webpack配置proxy 这种方式属于借助nodejs的跨域方式,在线上环境如果有部署nodejs服务的话,也可以使用nodejs代替nginx去配置跨域,但是比较麻烦不太推荐

{
    proxy:{
        '/api/xxx':{
            target:'//www.baidu.com/api',
             changeOrigin:true,
             logLevel:'debug'
        }
    }
}

总结

前端跨域的方式很多,但是最终采取哪种方式,需要结合我们的业务去确定;如果调用第三方服务,并且第三方只支持jsonp方式调用的那么就用jsonp;一般情况下用反向代理就行了,本地开发则使用devServer进行代理就足够了;