Giter Club home page Giter Club logo

koa_bff's People

Contributors

xiaohesong avatar

Stargazers

 avatar  avatar

Watchers

 avatar

koa_bff's Issues

koa自定义错误处理

因为这个是作为BFF去使用,所以需要处理一些自定义的错误消息。

客户端直接抛出错误,或者返回对应的状态码。

我们来写个axios的请求:

// myaxios.js
const axios = require('axios')
const instance = axios.create();
const FormData = require('form-data');

instance.interceptors.response.use(function (response) {
  return response;
}, function (error) {
  return Promise.reject(error);
});

const get = (path, params = {}, token) => {
  const searchParams = Object.keys(params).map(key => {
    return params[key] !== '' ? encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) : ''
  }).filter(item => item !== '').join('&')
  return instance.get(`${your api}/${path}?${searchParams}`, {
    headers: {
      'my-token': token
    }
  })
    .then(response => response.data)
    .catch(function (error) {
      throw error //注意,这里我们直接抛出异常,然后我们后面会去获取。
    });
}
exports.get = get


const post = (path, params, token = '') => {
  console.log("post form value is", params);
  let formData = new FormData();

  for (let filed in params) {
    formData.append(filed, params[filed]);
  }
  
  return instance({
      method: 'post',
      url: `${your url}/${path}`,
      data: formData,
      headers: {
        "my-token": 'token',
        'Content-Type': formData.getHeaders()['content-type']
      }
    })
    .then(response => response.data)
    .catch(function (error) {
      throw error
    });
}
exports.post = post



//users_controller.js
const {get} = require('./myaxios')
async function users(ctx) {
  const result = await get('users', ctx.params)
  if(result.code !== 200){
    //可以发现,这里你可以自己定义是否对客户端抛出异常, 默认是200
    ctx.body = loginer
    return
  }
  
  ctx.status = 200
  ctx.body = {code: 200, login: loginer.data, sysConfig: sysConfig.data}
}

exports.users = users 

看到这里,你应该要知道throwctx.throw的一些区别:

ctx.throw(404, '请求的资源不存在哦!')
//等同于下面的写法
const err = new Error('请求的资源不存在哦!');
err.status = 404;
err.expose = true;
throw err;

在koa里面,throw是默认为500状态。从官网里就可以知道

好了,在http里我们抛出异常,那么现在就可以去捕获这些异常进行处理了:

// errorMiddleware.js
const ERROR_502 = 'Network Error'

async function errorMiddleware(ctx, next){
  try {
    await next();
  } catch(error) {
    handleError(error, ctx)
  }
} 

function handleError(error, ctx) {
  console.log('出现异常,开始捕获', error.status);

  if (error.response) {
    checkReturnStatus(error.response, ctx)
  } else if (error.request) {
    if (error.message === ERROR_502) {
      throw error.message
    }
    throw error
  } else {
    throw error
  }
}


function checkReturnStatus(res, ctx) {
  let result = {code: res.status, msg: `${res.status}, ${res.statusText}`, data: ''}

  ctx.status = res.status
  ctx.body = result 
}

exports.errorMiddleware = errorMiddleware

从上面发现,主要是针对response错误进行了处理,其他的一律是500的状态码去返回。

注意: 这里的错误处理只是示例,针对于http的请求。你还需要考虑到非http的。比如一些其他的typeerror之类的。

最后我们就可以使用这个错误处理的中间件了:

// server.js
const Koa = require('koa');
const {errorMiddleware} = require('./errorMiddleware')
const app = new Koa();
...
app.use(errorMiddleware)
...

这样就可以处理了

docker部署之后502

这个被坑到了,部署之后网页显示502。

进入容器查看日志,没有错误没有输出。

然后本地build:

docker build --build-arg app_env=staging -t koa_bff_staging_build .
docker run koa_bff_staging_build

可以发现,我直接通过IP是访问不了的。然后google之后发现了解决方案

之后修改之后再部署,果然就可以了。

修改的位置在启动的config

koa保存文件到服务器

这里接收文件,使用koa-body去获取form-data得数据。

app.use(koaBody({
  multipart: true,
  formidable: {
      maxFileSize: 200*1024*1024	// 设置上传文件大小最大限制,默认2M
  }
}));

xxx_controller.js

const uuidv1 = require('uuid/v1');
const path = require('path');
var fs = require('fs');

async function index(ctx) {
  const uid = uuidv1()
  const file = ctx.request.files.file
  const type = ctx.request.body.type
  const fileName = file.name

  saveFile({file, type, uid})

  ctx.body = {
    message: `已接收到${fileName}, 即将处理, ${uid}`,
    status: true
  }
}

function saveFile({file, type, uid}) {
  const basicPath = `../../../files/`
  const filesPath = buildFolder(basicPath)
  if (!fs.existsSync(filesPath)){
    console.log('不存在的地址', filesPath);
    fs.mkdirSync(filesPath);
  }
  const typePath = buildFolder(`${basicPath}${type}`)
  if (!fs.existsSync(typePath)){
    console.log('不存在的地址', typePath);
    fs.mkdirSync(typePath);
  }
  const ext = file.name.split('.').pop()
  const reader = fs.createReadStream(file.path);
  const stream = fs.createWriteStream(path.resolve(__dirname, `${basicPath}${type}/${uid}.${ext}`));
  reader.pipe(stream);
}

function buildFolder(url) {
  return path.resolve(__dirname, `${url}`)
}

koa文件下载

此koa的应用仅仅是作为中转使用,所以我只需要获取到上游服务器的文件内容,然后返回就好:

async function toExport(ctx) {
  const filename = encodeURIComponent(ctx.query.filename || '导出数据')
  //下面这些东西,其实是用不到的,但是如果你需要,你可以根据自己的情况来设置
  // ctx.set('Content-disposition', `attachment;filename=${filename}.xlsx`);
  // ctx.set('Content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheets');
  const result = await exporter(`v1/contracts/export`, ctx.query, ctx.headers['token'])
  ctx.body = result
}
exports.export = toExport 

// server axios.js
const exporter = (path, params = {}, token) => {
  const searchParams = Object.keys(params).map(key => {
    return encodeURIComponent(key) + '=' + encodeURIComponent(params[key])
  }).join('&')
  return instance.get(`${API_URL}/${path}?${searchParams}`, {
      responseType: 'stream',
      headers: {
        'token': token,
        'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      }
    })
    .then(response => response.data)
    .then(stream => stream)
    .catch(function (error) {
      handleError(error) //自定义方法处理错误
    });
}
exports.exporter = exporter

然后客户端就正常下载,譬如:

// client axios.js
export const exporter = (path, params = {}, fileName='导出数据') => {
  params.filename = fileName
  const searchParams = Object.keys(params).map(key => {
    return encodeURIComponent(key) + '=' + encodeURIComponent(params[key])
  }).join('&')
  return instance.get(`${API_URL}/${path}?${searchParams}`,{
    responseType: 'blob',
    headers: {
      'token': localStorage.getItem("token"),
      'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    }
  })
  .then(response => response.data)
  .then(blob => {
    let url = window.URL.createObjectURL(blob);
    let a = document.createElement('a');
    a.href = url;
    a.download = `${fileName}.xlsx`;
    a.click();
    Promise.resolve(blob);
  })
  .catch(function (error) {
    handleError(error)
  });
}

可以发现,两个responseType的不同,blob是去获取文件对象,stream是获取文件流。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.