同源与跨域

91 阅读3分钟

同源策略

同源策略是浏览器的一种自我保护行为。用于限制在Web浏览器中加载和执行来自不同源(来源)的资源。所谓的同源指的是:协议域名端口均要相同。

浏览器中大部分内容都是受同源策略的限制的,除了以下三个标签:

<img src="..." />
<link href="..." /> 
<script src="..."></script>

跨域

但有些时候,我们又确实需要访问一些跨域资源,那怎么办呢? 那就需要跨域!所谓跨域就指的是去向一个非本源的目标地址发送请求的过程!跨域的解决方案如下:

(1) jsonp 【前后端配合】

jsonp 实际上就是通过 script 标签的 src 去请求数据,因为 script 标签的请求不会被同源策略所限制!再通过 callback 函数实现对数据的获取!(这种方式需要后端进行配合,后端在前端进行对应请求的时候返回对应的jsonp格式)

前端写法如下:

<script type="text/javascript">
function callbackFunction(result, methodName) { ///result 指向对应数据 
} 
</script> 
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script>

(2) CORS 【后端】

CORS 跨域资源共享,通过服务器的响应头进行配置!即服务器自身指定允许哪些域可以对自己进行访问!

配置的值可以是固定的白名单ip或者通配符,可以用通配符"*",代表接受所有请求。

CORS 对于简单请求和复杂请求的处理方式不同!

简单请求: 【mdn定义的简单请求就是不会触发 cors 预检的请求】

  • 请求方法为 :GET、HEAD、POST
  • 请求头只能设置:Accept、Accept-Language、Content-Language、Content-Type
    • 且 Content-Type 的值只能是: application/x-www-form-urlencoded、 multipart/form-data、 text/plain

后端只需要配置响应头Access-Control-Allow-Origin

'Access-Control-Allow-Origin''xxx'

预检请求:

预检请求是指在发送跨域请求前,浏览器会先发送一个OPTIONS请求,询问服务器是否允许该跨域请求。如果服务器返回的响应头中包含了CORS相关的设置,并且服务器认为该跨域请求是合法的,浏览器才会发送真正的请求。这个预检请求的过程就是CORS中的预检过程,也被称为CORS预检。

  • 请求方法为:PUT、DELETE、CONNECT、OPTIONS、TRACE
  • 请求头中设置了除了上述的任意多项
  • Content-Type设置了简单请求不允许的值,如常用的application/json

后端需要配置的响应头就要多一点了:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
  • Access-Control-Allow-Methods代表可接受methods

  • Access-Control-Allow-Headers代表可接受的headers修改

  • Access-Control-Max-Age代表预检的残留时间,代表预检之后可以免预检的时间

(3) 代理

3.1 webpack-dev-server

在webpack.config.js中配置代理如下:

devServer: { 
// ...其他配置 
proxy: {
    '/api': {
    target: 'http://api.example.com/', // 要代理到的地址 
    pathRewrite: { '^/api': '' }, // 将/api开头的路径去掉           changeOrigin: true, // 是否跨域 
  },
 },
}
3.2 node.js 中间件 http-proxy-middleware

在代码中配置如下:

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware'); 
const app = express(); 
app.use('/api', createProxyMiddleware({ 
target: 'http://api.example.com', 
changeOrigin: true, 
pathRewrite: { 
  '^/api': ''
  }
})); 
app.listen(3000, () => { 
console.log('Server is running on port 3000'); 
});
3.3 Nginx 反向代理

Nginx实现跨域

(4) 解决方案对比

  • jsonp 只支持get请求,无法支持复杂的请求
  • webpack-dev-server 只支持线上环境
  • node 、nginx 相对较好,当然实现起来也更复杂!