前后端交互3:CORS,正反向代理以及jwt鉴权

CORS

  • 是W3C标准 CORS(Cross-origin resource sharing),跨域资源共享
  • 是一份浏览器技术的规范,用来避开浏览器的同源策略
  • 简单来说就是解决跨域问题的除了jsonp外的另一种方法;比jsonp更加优雅

简单请求

简单请求的条件

请求方法
  1. HEAD
  2. GET
  3. POST
头信息
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

配置简单请求

1. 设置允许的 origin:

Access-Control-Allow-Origin: *

res.header('Access-Control-Allow-Origin', 'http://www.baidu.com'); //这样写,只有www.baidu.com 可以访问。
res.header('Access-Control-Allow-Origin', '*'); //这个表示任意域名都可以访问。

前端get请求跨域资源

      // 非同源getData
      function onNoHomologous() {
        const xhr = new XMLHttpRequest();
        xhr.open("get", "http://localhost:8081/getData");
        xhr.onload = (e) => {
          console.log(xhr.response);
        };
        xhr.send();
      }

被请求的后端服务器设置响应头,允许跨域资源的请求,(让浏览器放行)

router.get("/getData", ctx => {
  ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
  ctx.body = "get - data - 8081";
});
2.设置允许requset设置的头部

Access-Control-Allow-Headers :

res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
3. 允许客户端获取的头部key

Access-Control-Expose-Headers

 ('Access-Control-Expose-Headers''Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild')

CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。

前端想获取到响应的头部信息

      const xhr = new XMLHttpRequest();
      xhr.open("get", "http://localhost:8081/getData");
      xhr.onload = (e) => {
        console.log(xhr.getAllResponseHeaders());
      };

后端设置可获取的头部字段,放行给客户端

 ctx.set("Content-Language", "ch");
 ctx.set("Access-Control-Export-Headers", "Content-Language")

在这里插入图片描述

4. 允许携带Cookies
  • server 后端字段
    Access-Control-Allow-Credentials: true
  • client 前端配置
    xhr.withCredentials = true

前端跨域登录,需要设置允许携带cookies

    function onLogin() {
      const xhr = new XMLHttpRequest();
      xhr.open("post", "http://localhost:8081/login");
      xhr.withCredentials = true;	// 允许cookies
      xhr.onload = (e) => {
        console.log(xhr.response);
      };
      xhr.send();
    }

后端处理请求,设置cookies,放行cookies

router.post("/login", ctx => {
  ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
  ctx.set("Access-Control-Allow-Credentials", true);
  ctx.cookies.set("uId", 1);
  ctx.body = "login OK";
});

在这里插入图片描述
在这里插入图片描述

非简单请求(预检请求)

在这里插入图片描述

后端配置预检请求头

  1. 设置允许的HTTP方法
    Access-Control-Allow-Methods
  2. 设置允许请求的头额外发送的头信息字段
    Access-Control-Allow-Headers
  3. 有效期(秒)
    Access-Control-Max-Age

PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH

配置非简单请求

发送非同源post-data,json格式

    function onNoPost() {
      const xhr = new XMLHttpRequest();
      xhr.open("post", "http://localhost:8081/postData");
      xhr.onload = (e) => {
        console.log(xhr.response);
      };

      const data = {
        name: "xiaohong",
        pwd: "123",
      };

      xhr.setRequestHeader("content-type", "application/json");
      xhr.send(JSON.stringify(data));
    }

在这里插入图片描述
这类请求会有一个预检options请求,后端服务器需要设置通过这个options

router.options("/postData", ctx => {
  ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
  ctx.set("Access-Control-Allow-Methods", "POST");
  ctx.set("Access-Control-Allow-Headers", "content-type");
  ctx.body = "";
});

再设置post请求

router.post("/postData", (ctx) => {
  ctx.set("Access-Control-Allow-Origin", "http://localhost:8080");
  const { name, pwd } = ctx.request.body;
  ctx.body = {
    name,
    pwd,
  };
});

在这里插入图片描述

代理

两种代理方式

  1. 正向代理
    在这里插入图片描述
  2. 反向代理
    由proxy来选择服务器地址
    在这里插入图片描述

利用axios代理实现跨域访问

前端发送跨域请求

  <script>
    function onGetData() {
      const xhr = new XMLHttpRequest();

      xhr.open("get", "/getData");
      xhr.onload = () => {
        console.log(xhr.response);
      };
      xhr.send();
    }
  </script>

后端利用axios 内置模块代理

const axios = require('axios');

const router = new Router();
// 当前服务器是 8080
router.get("/getData", async (ctx) => {
  // 帮助我们去请求 8081 数据
  const res = await axios.get("http://localhost:8081/getData");
  ctx.body = res.data;
});

利用koa-server-http-proxy实现代理

这个库只需要在需要代理的地址前面做上标记就行了
后端将标记设置为api

const proxy = require('koa-server-http-proxy');

重写路径的格式^/api

app.use(proxy("/api",{
    // 设置api
    target:"http://localhost:8081",
    // 重写路径,去掉/api
    pathRewrite:{
        "^/api":""
    }
}))

前端跨域请求时带上/api就能代理了

    function onGetData() {
      const xhr = new XMLHttpRequest();

      xhr.open("get", "/api/getData");
      xhr.onload = () => {
        console.log(xhr.response);
      };
      xhr.send();
    }

在这里插入图片描述

JsonWebToken(jwt鉴权)

json web token是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准

原理

  • 服务器认证以后,生成一个 JSON 对象,发回给用户
  • 用户与服务端通信的时候,需要发回这个 JSON 对象
  • 服务器完全只靠这个对象认定用户身份
  • 防止用户篡改数据,服务器在生成这个对象的时候,会加上签名

jsonwebtoken 原生模块

登录

服务端设置密匙,生成秘钥,前端将token存入到localstorage

const jwt = require("jsonwebtoken");

服务端设置个秘钥

const secret = "webtoken123123";

登录时生成钥匙

router.post("/login", (ctx) => {
  // 生成钥匙
  const token = jwt.sign(
    {
      uId: "123",
    },
    secret,
    {
      expiresIn: "2h",	// 过期时间
    }
  );

  ctx.body = {
    state: 1,
    body: {
      token,
    },
  };
});

在这里插入图片描述
通过jwt.io网站来分析下这个token
在这里插入图片描述
前端将token存入localstorage

    function onLogin() {
      const xhr = new XMLHttpRequest();
      xhr.open("post", "/login");
      xhr.onload = (e) => {
        console.log(xhr.response);

        const res = JSON.parse(xhr.response);
        console.log(res);
        const token = res.body.token;
        localStorage.setItem("token", token);
      };
      const data = {
        name: "super",
        passwd: "123",
      };
      xhr.setRequestHeader("content-type", "application/json");
      xhr.send(JSON.stringify(data));
    }

在这里插入图片描述

验证

前端需要将存储的token加到请求头字段Authorization里:

    function onGetData() {
      const xhr = new XMLHttpRequest();
      xhr.open("get", "/getData");
      xhr.onload = (e) => {
        console.log(xhr.response);
      };
      const token = localStorage.getItem("token");
      xhr.setRequestHeader("Authorization", token);
      xhr.send();
    }

在这里插入图片描述
服务端需要对这个token进验证

router.get("/getData", (ctx) => {
  // 验证钥匙对不对
  const token = ctx.get("Authorization");
    jwt.verify(token, secret, (err, decoded) => {
      if (err) {
        ctx.throw(err);
      }

      ctx.body = {
        data: {
          decoded,
        },
      };
    });
});

在这里插入图片描述

koa-jwt

帮助我们验证token

const koaJwt = require('koa-jwt');
app.use(koaJwt({
    secret
}))

注意前端的请求头格式
Bearer 后面有个括号

xhr.setRequestHeader("Authorization", "Bearer " + token);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值