解决跨域请求的几种常用方式

3,297 阅读3分钟

这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

现象

我们经常在开发中遇到跨域请求,导致我们的请求不能发送到服务端,服务端没有收到请求,导致请求失败。

为什么会有跨域请求?什么是跨域请求?该怎么解决跨域请求?

跨域请求

因为浏览器的同源策略,限制只能同域名请求同域名的接口,如果请求非同域名下的接口,那么就会报错。

image.png

因为这个同源策略,可以保护网站的接口不用随便被别人调用,在浏览器的层面及时拦截,在一定程度上起来保护作用。

那什么样的请求算是跨域请求?

本身的url和请求的接口需要同时满足以下

  • 端口一致
  • 协议一致
  • 域名一致

这样就不是跨域请求。只要你不符合上面任何一条,那么你这个请求就是跨域请求,浏览器就会拦截报错。

但是我们有时候页面部署在一台服务器,接口在另外一台服务器,这样就不能满足上面的规则,该怎么解决这种正常的业务需求,防止被浏览器拦截呢?

cors

这个会用的比较多,跨域资源共享, 全称 Cross-origin resource sharing,这是一个W3C标准,浏览器访问到你的接口已经开启了cors,并且你的url是在许可内,则浏览器不会拦截,允许访问。

配置字段:

'Access-Control-Allow-Origin': '*', // 支持的域名, *代表任意域名都可以访问
'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type' // 支持的header
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS', //支持的请求方式

补充:

node的配置 - koa

const Koa = require('koa');
const app = new Koa()
app.use(async (ctx, next) => {
  ctx.set('Access-Control-Allow-Origin', '*');
  ctx.set('Access-Control-Allow-Headers', 'content-type');
  ctx.set('Access-Control-Allow-Methods', 'POST');
  next()
});

node的配置 - express

const express = require('express')
const app = new express()
app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Headers', 'content-type')
  res.header('Access-Control-Allow-Methods', 'PUT')
  next()
})

目前也有一些库已经实现了cors,比如

express的cors

const cors = require('cors')
const app = express()
app.use(cors())

koa的@koa/cors

const Koa = require('koa');
const cors = require('@koa/cors')
app.use(cors())

如果需要携带cookie,需要加上Access-Control-Allow-Credentials: true,此时Access-Control-Allow-Origin不能设置*

nginx转发

因为跨域请求是在浏览器层面才会限制,但是在服务端是不会有限制,所以我们通过请求同源的接口地址,然后在同源的服务器上通过nginx来转发我们的请求到目标服务器上,得到返回结果后再返回。

nginx.conf的配置

http {
    server {
         // xxx是具体的接口
         location /xxx/ {
             proxy_pass url // url是目标的地址
         }   
    }
}
                          

JSONP

浏览器虽然对接口请求有同源策略限制,但是对script标签,img标签是没有限制,它们的src可以是别的域名的地址。

具体是把我们的请求地址通过script的src发送给服务端,服务端收到请求后,然后把返回接口通过参数,调用我们定义的全局函数返回到页面。

<script src="具体的接口地址?callback=xxx">
window.xxx = (res) {
    console.log(res)
}

JSONP只能对get请求有效。

这3种方式我在业务中用的比较多。