跳转到内容
返回

关于跨域

跨域

跨域是浏览器为了保证服务数据的安全性,而存在的一种限制请求的一种机制,只存在于浏览器。

主要工作原理就是根据有没有遵循同源策略(当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域),来判断一个请求是否跨域,然后决定是否允许这个请求。

同源策略

概念

同源策略会限制的内容

同源策略下有几个允许跨域加载资源的方式:

跨域限制

跨域不仅对请求有限制,对请求的方法和发送的内容格式,也会有限制;除过默认允许的一些外,其他的非默认请求方法和内容格式都需要在服务端进行设置允许这些对应的可以访问。

因为非默认的请求方法和内容类型会在正式发送该请求前,发送一个预请求,来判断服务端是否允许该请求的访问,之后再发送该请求,如果服务端允许就正常获取响应内容,不允许就会报错,如下图。 不允许put访问

服务端允许后允许访问,可以看到会有2个请求,第一就是预请求,第二个是正式发送的请求,预请求的方法是会显示OPTIONS。 允许访问 允许访问

设置代码(以node为例)

const koa = require("koa");
const app = new koa();

app.use(async ctx => {
  console.log(ctx.request.url);
  ctx.response.status = 200;
  // 设置允许跨域
  ctx.response.set({
    // 允许跨域访问的域名
    "Access-Control-Allow-Origin": "*",
    // 当请求方法是跨域默认请求之外的请求时,服务器需要设置对应的允许的请求方法
    "Access-Control-Allow-Methods": "PUT",
    // 允许该请求在第一次请求成功后的1000秒内,不需要再发送预请求
    "Access-Control-Max-Age": "1000",
  });
  ctx.response.body = "hi";
});

app.listen(3000, () => {
  console.log("ok");
});

列举一下跨域默认不需要预请求就可以发送的方法(Mthods)和内容类型(Content-Type)

跨域默认允许的请求方法(Method)

默认允许的发送请求内容类型(Content-Type)

默认允许的请求头

更多

常见跨域场景

跨域

浪里行舟大佬的一些说明

第一:如果是协议和端口造成的跨域问题“前台”是无能为力的。

第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。

这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

解决方案

JSONP

1.利用<script src=’***‘>可以跨域请求资源的原理2.这种方式只能通过GET请求。3.但是适配较广

代码

...
<body>
  <button id="btn">请求</button>
  <script>
    let btn = document.querySelector("#btn");
    btn.onclick = function () {
      // 创建一个script标签块
      let frame = document.createElement("script");
      // 设置src链接
      // http://localhost:3000/person为请求借口
      // ? 分隔符
      // callback=func传给后端的一个回调函数
      frame.src = "http://localhost:3000/person?callback=func";
      // 添加到body内
      document.querySelector("body").append(frame);
    };
    function func(res) {
      // 后端成功收到请求后 会返回并执行 该函数
      console.log(res); // 打印收到的数据
    }
  </script>
</body>
...
...
let data=require('data.json');
route.get('/person', async (ctx) => {
    newData = JSON.stringify(data);
    // 执行前端传递来的函数 并把数据作为参数传递
    ctx.body = `func(${newData})`;
})
...

CROS

什么是CROS

使用:

<button id="btn">send</button>
<script>
  let btn = document.querySelector("#btn");
  btn.onclick = function () {
    getData();
  };
  let getData = () => {
    fetch("http://localhost:3000/person", {
      method: "GET",
    })
      .then(res => res.json())
      .then(data => {
        console.log(data);
      })
      .catch(err => {
        console.log(err);
      });
  };
</script>
const cors = require("koa2-cors");
// 使用cors中间件
app.use(
  cors({
    // 允许get方法跨域请求
    allowMethods: ["GET"],
    // 在koa中不适用中间件 可以使用上下文对象来自己设置
    // ctx.set(...);
  })
);

Node/nginx做代理

因为服务器之间不用遵守同源策略,所以可以通过node或者nginx来转发请求,实现跨域

步骤

其他方式尝试后更新



上一篇
关于meta
下一篇
vuejs基础复习4---生命周期函数
×