koa接口代理例子

接口代理的概念

正向代理

  代理客户端去请求服务器,隐藏了真实客户端,服务器并不知道真实的客户端是谁。

反向代理

  反向代理隐藏了真正的服务端,就像你每天使用百度的时候,只知道敲打www.baidu.com就可以打开百度搜索页面,但背后成千上万台百度服务器具体是哪一台为我们服务的,我们并不知道。我们只知道这个代理服务器,它会把我们的请求转发到真实为我们服务的那台服务器那里去。

接口代理的简单实现

  一般来说,前端开发者多用正向代理的接口代理方式。所以实现的时候需要一个服务端和一个客户端。

客户端

客户端向服务端发起请求:

import axios from 'axios'
// 以/github/开头的url被认为是需要代理的接口
axios
     .get('/github/search/repositories?q=react')
     .then(res => console.log(res))
服务端

  服务端接收到客户端的请求之后,根据路径或其他的参数进行真正的请求路径的拼接,设置相关的字段之后,由服务器发起对外网服务器的请求,再由服务器返回外网服务器返回的数据给客户端。

// proxy.js
/**
 * github接口代理,防止因请求过多而被禁用ip,并且添加认证头部
 */

const githubBaseUrl = 'https://api.github.com';
const axios = require('axios');
module.exports = server => {
  server.use(async (ctx, next) => {
    const path = ctx.path;
    // path以/github/开头,则被认为是一个需要代理的接口
    if (path.startsWith('/github/')) {
      // 获取当前的token和token_type
      const githubAuth = ctx.session.githubAuth;
      // 对应的github接口地址
      const githubPath = `${githubBaseUrl}${ctx.url.replace('/github/', '/')}`;
      const token = githubAuth && githubAuth.access_token;
      // 根据token的有无增加字段
      let headers = {};
      if (token) {
        headers['Authorization'] = `${githubAuth.token_type} ${token}`
      }
      try {
        const res = await axios({
          method: 'get',
          url: githubPath,
          headers
        });
        if (res.status === 200) {
          // 返回数据
          ctx.body = res.data;
          // 设置响应头
          ctx.set('Content-Type', 'application/json')
        } else {
          ctx.status = res.status;
          ctx.body = {
            success: false,
          };
          ctx.set('Content-Type', 'application/json')
        }
      } catch (e) {
        ctx.body = {
          success: false,
        };
        ctx.set('Content-Type', 'application/json')
      }
    } else {
      await next()
    }
  })
};

// server.js
const Koa = require('koa');
const Router = require('koa-router');
const server = new Koa();
const router = new Router();
server.use(router.routes());
const proxy = require('./proxy');
proxy(server)

补充

  接口代理正常来讲是没问题的,但是针对客户端渲染和服务端渲染的代理方式是不一样的。因为客户端渲染时,请求代理服务器会自动加上http://localhost的路径,解释到服务端的路径为http://127.0.0.1:80,这样的话就存在跨域问题,所以我们需要分开设置服务端的代理请求和客户端的代理请求。

客户端的接口代理

client.js:client发起对githubAPI发起请求,不过我们只是将发起请求的一些参数传递到request方法。由request方法判断服务端和客户端的请求。

const {request} = require('../lib/api');
const Index = (props) => {
  console.log(props);
  return (
      <span>index</span>
  )
};

Index.getInitialProps = async (ctx) => {
  let res = await request({
    url: '/search/repositories?q=react',
  }, ctx.req, ctx.res);
  return {
    data: res.data
  }
};

api.js

const axios = require('axios');
// 判断是否是服务端的接口代理
const isServer = typeof window === 'undefined';
/**
* request用于客户端的接口代理api,已经分服务端和客户端处理请求
* @param method 请求类型
* @param url 请求路径
* @param data 请求发送的数据
* @param req node原生环境req
* @param res node原生环境res
* @returns {Promise<*>}
*/
async function request({method = 'GET', url, data = {}}, req, res) {
  // 服务端的情况
  if (isServer) {
    let headers = {};
    // 取得session中得githubAuth
    const session = req.session;
    const githubAuth = session && session.githubAuth;
    // 根据access_token得有无添加header字段
    if (githubAuth && githubAuth.access_token) {
      headers['Authorization'] = `${githubAuth.token_type} ${githubAuth.access_token}`
    }
    // 根据已处理好得参数,请求Github
    return await requestGithub(method, url, data, headers)
  } else {
    // 如果是客户端得得接口代理,则直接进行/github/xxx的axios请求,
    // 当进行这个请求时会被/github/xxx的拦截器拦截到,进而发起真正的api请求
    return await axios({
      method,
      // 拼接url
      url: `/github${url}`,
      data
    })
  }
}

const githubBaseUrl = `https://api.github.com`;
/**
* 请求github
* @param method 方法
* @param url 路径
* @param data 数据
* @param headers 请求头
* @returns {Promise<void>}
*/
async function requestGithub(method, url, data, headers) {
  if (url) {
    return await axios({
      method,
      // 拼接url
      url: `${githubBaseUrl}${url}`,
      data,
      headers
    })
  } else {
    throw Error('url must required')
  }
}

module.exports = {
  request, requestGithub
};

proxy.js

/**
 * github接口代理,防止因请求过多而被禁用ip,并且添加认证头部
 */
const {requestGithub} = require('../lib/api');
const githubBaseUrl = 'https://api.github.com';
const axios = require('axios');
module.exports = server => {
  server.use(async (ctx, next) => {
    const path = ctx.path;
    // 当客户端的请求被拼接上/github/的url时,被该api拦截,进行请求头的设置,然后再请求github
    if (path.startsWith('/github/')) {
      const {method} = ctx;
      const githubAuth = ctx.session && ctx.session.githubAuth;
      // 对应的github接口地址
      const githubPath = `${githubBaseUrl}${ctx.url.replace('/github/', '/')}`;
      const token = githubAuth && githubAuth.access_token;
      // 根据token的有无增加字段
      let headers = {};
      if (token) {
        headers['Authorization'] = `${githubAuth.token_type} ${token}`
      }
      const res = await requestGithub(method, githubPath, {}, headers);
      ctx.status = res.status;
      ctx.body = res.data;
    } else {
      await next()
    }
  })
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值