1
头图

Project Background

图片

For the pictures and other resources that are often used in the front-end development process, in addition to using common third-party map beds, we can also build a private map bed by ourselves to provide the team with front-end basic services. This article aims to review and summarize the implementation plan of the back-end part of the self-built map bed, hoping to give some reference and solutions to students with similar needs. In addition, because it is a front-end infrastructure, here we completely use node.js, which is familiar to front-end students, to achieve the required back-end service requirements.

plan

The back-end part of the architecture selection, because it mainly provides infrastructure services for front-end business developers, and the group platform also provides various cloud services, and there will not be too many high concurrency scenarios, so the language selection is still Mainly node.js, which is familiar to front-end students, here our team mainly uses the express framework. In the entire large private network technical team, the back-end is still dominated by java, and node is mainly used as the middle layer BFF. Some interfaces are developed and aggregated, so the main body is still based on the monolithic architecture, and the micro-service form uses the cloud service products of service mesh (such as: istio) to cooperate with Java students, instead of using some node.js micro-services Framework (eg: nest.js has microservice-related settings, and seneca, etc.). Since it is a single application, in view of the middleware mechanism of express, different modules are separated through routing, and the services provided in this image bed service are all isolated under the imagepic module; in terms of database selection, the image bed only needs an identification There are no special additional persistence requirements. Here I choose mongodb as the database persistent data (ps: the mongodb provided by the cloud middleware has access problems, and will be implemented through CFS (file storage system) + FaaS later. Due to the particularity of the picture bed function, the uploaded pictures are streamed, and a temporary picture storage process will be used here, which will be persistently stored through the CFS (file storage system) of cloud products. Delete data; and the real image storage is placed in COS (object storage). Compared with the CFS file interface specification, COS is based on Amazon's S3 specification, so it is more suitable for image storage. carrier

图片

content

  • db

    • \_\_temp\_\_
    • imagepic
  • deploy

    • dev

      • Dockerfile
      • pv.yaml
      • pvc.yaml
      • server.yaml
    • production

      • Dockerfile
      • pv.yaml
      • pvc.yaml
      • server.yaml
    • build.sh
  • faas

    • index.js
    • model.js
    • operator.js
    • read.js
    • utils.js
    • write.js
  • server

    • api

      • openapi.yaml
    • lib

      • index.js
      • cloud.js
      • jwt.js
      • mongodb.js
    • routes

      • imagepic

        • auth
        • bucket
        • notification
        • object
        • policy
        • index.js
        • minio.js
      • router.js
    • utils

      • index.js
      • is.js
      • pagination.js
      • reg.js
      • uuid.js
    • app.js
    • config.js
    • index.js
  • main.js

practice

图片

Authentication judgment is required for some interfaces involved. Here, jwt is used to perform relevant permission verification.

source code

faas

Cloud functions are abstracted here to provide capabilities for back-end services and simulate some database operations related to mongodb.

model.js

Defined model-related data format

/**
 * documents 数据结构
 * @params
 * _name        String 文件的名称
 * _collections Array  文件的集合
 * @examples
 * const documents = {
 *    "_name": String,
 *    "_collections": Array
 * }
 */
exports.DOCUMENTS_SCHEMA = {
    "_name": String,
    "_collections": Array
}

/**
 * collections 数据结构
 * @params
 * _id String 集合的默认id
 * _v  Number 集合的自增数列
 * @examples
 * const collections = {
 *    "_id": String,
 *     "_v": Number,
 * }
 */
 exports.COLLECTIONS_SCHEMA = {
    "_id": String
}

read.js

Node's fs module read file operations

const { 
    isExit,
    genCollection,
    genDocument,
    findCollection,
    findLog,
    stringify,
    fs,
    compose,
    path
} = require('./utils');

exports.read = async (method, ...args) => {
    let col = '', log = '';
    const isFileExit = isExit(args[0], `${args[1]}_${args[2]['phone']}.json`);
    console.log('isFileExit', isFileExit)
    const doc = genDocument(...args);
    switch (method) {
        case 'FIND':
            col = compose( stringify, findCollection )(doc, genCollection(...args));
            log = compose( stringify, findLog, genCollection )(...args);
            break;
    };

    if(isFileExit) {
        return fs.promises.readFile(path.resolve(__dirname, `../db/${args.slice(0,2).join('/')}_${args[2][`phone`]}.json`), {encoding: 'utf-8'}).then(res => {
            console.log('res', res);
            console.log(log)
            return {
                flag: true,
                data: res,
            };
        })
    } else {
        return {
            flag: false,
            data: {}
        };
    }
};

write.js

Write file operation of node's fs module

const {
    isExit,
    fs,
    path,
    stringify,
    compose,
    genCollection,
    addCollection,
    addLog,
    updateCollection,
    updateLog,
    removeCollection,
    removeLog,
    genDocument
} = require('./utils');

exports.write = async (method, ...args) => {
    console.log('write args', args, typeof args[2]);
    const isDirExit = isExit(args.slice(0, 1));
    const doc = genDocument(...args);
    let col = '', log = '';
    switch (method) {
        case 'ADD':
            col = compose( stringify, addCollection )(doc, genCollection(...args));
            log = compose( stringify, addLog, genCollection )(...args);
            break;
        case 'REMOVE':
            col = compose( stringify, removeCollection )(doc, genCollection(...args));
            log = compose( stringify ,removeLog, genCollection )(...args);
            break;
        case 'UPDATE':
            col = compose( stringify, updateCollection )(doc, genCollection(...args));
            log = compose( stringify, updateLog, genCollection )(...args);
            break;
    }

    if (!isDirExit) {
        return fs.promises.mkdir(path.resolve(__dirname, `../db/${args[0]}`))
            .then(() => {
                console.log(`创建数据库${args[0]}成功`);
                return true;
            })
            .then(flag => {
                if (flag) {
                    return fs.promises.writeFile(path.resolve(__dirname, `../db/${args.slice(0,2).join('/')}_${args[2][`phone`]}.json`), col)
                        .then(() => {
                            console.log(log);
                            return true;
                        })
                        .catch(err => console.error(err))
                }
            })
            .catch(err => console.error(err))
    } else {
        return fs.promises.writeFile(path.resolve(__dirname, `../db/${args.slice(0,2).join('/')}_${args[2][`phone`]}.json`), col)
            .then(() => {
                console.log(log)
                return true;
            })
            .catch(err => console.error(err))
    }
};

operator.js

const { read } = require('./read');

const { write } = require('./write');

exports.find = async (...args) => await read('FIND', ...args);

exports.remove = async (...args) => await write('REMOVE', ...args);

exports.add = async (...args) => await write('ADD', ...args);

exports.update = async (...args) => await write('UPDATE', ...args);

utils.js

shared toolkit

const { DOCUMENTS_SCHEMA, COLLECTIONS_SCHEMA } = require('./model');

const { v4: uuidv4 } = require('uuid');

const path = require('path');

const fs = require('fs');

exports.path = path;
exports.uuid = uuidv4;
exports.fs = fs;

exports.compose = (...funcs) => {
    if(funcs.length===0){
        return arg=>arg;
    }
    if(funcs.length===1){
        return funcs[0];
    }
    return funcs.reduce((a,b)=>(...args)=>a(b(...args)));
};

exports.stringify = arg => JSON.stringify(arg);

exports.isExit = (...args) => fs.existsSync(path.resolve(__dirname, `../db/${args.join('/')}`));

console.log('DOCUMENTS_SCHEMA', DOCUMENTS_SCHEMA);

exports.genDocument = (...args) => {
    return {
        _name: args[1],
        _collections: []
    }
};

console.log('COLLECTIONS_SCHEMA', COLLECTIONS_SCHEMA);

exports.genCollection = (...args) => {
    return {
        _id: uuidv4(),
        ...args[2]
    }
};

exports.addCollection = ( doc, col ) => {
    doc._collections.push(col);
    return doc;
};

exports.removeCollection = ( doc, col ) => {
    for(let i = 0; i < doc._collections.length; i++) {
        if(doc._collections[i][`_id`] == col._id) {
            doc._collections.splice(i,1)
        }
    }
    return doc;
};

exports.findCollection = ( doc, col ) => {
    return doc._collections.filter(f => f._id == col._id)[0];
};

exports.updateCollection = ( doc, col ) => {
    doc._collections = [col];
    return doc;
};

exports.addLog = (arg) => {
    return `增加了集合 ${JSON.stringify(arg)}`
};

exports.removeLog = () => {
    return `移除集合成功`
};

exports.findLog = () => {
    return `查询集合成功`
};

exports.updateLog = (arg) => {
    return `更新了集合 ${JSON.stringify(arg)}`
};

lib

cloud.js

Business operations use cloud functions

const {
  find,
  update,
  remove,
  add
} = require('../../faas');

exports.cloud_register = async (dir, file, params) => {
  const findResponse = await find(dir, file, params);
  if (findResponse.flag) {
    return {
      flag: false,
      msg: '已注册'
    }
  } else {
    const r = await add(dir, file, params);
    console.log('cloud_register', r)
    if (r) {
      return {
        flag: true,
        msg: '成功'
      }
    } else {
      return {
        flag: false,
        msg: '失败'
      }
    }
  }
}

exports.cloud_login = async (dir, file, params) => {
  const r = await find(dir, file, params);
  console.log('cloud_read', r)
  if (r.flag == true) {
    if (JSON.parse(r.data)._collections[0].upwd === params.upwd) {
      return {
        flag: true,
        msg: '登录成功'
      }
    } else {
      return {
        flag: false,
        msg: '密码不正确'
      }
    }
  } else {
    return {
      flag: false,
      msg: '失败'
    }
  }
}

exports.cloud_change = async (dir, file, params) => {
  const r = await update(dir, file, params);
  console.log('cloud_change', r)
  if (r) {
    return {
      flag: true,
      msg: '修改密码成功'
    }
  } else {
    return {
      flag: false,
      msg: '失败'
    }
  }
}

jwt.js

jwt verification related configuration

const jwt = require('jsonwebtoken');
const {
    find
} = require('../../faas');

exports.jwt = jwt;

const expireTime = 60 * 60;

exports.signToken = (rawData, secret) => {
    return jwt.sign(rawData, secret, {
        expiresIn: expireTime
    });
};

exports.verifyToken = (token, secret) => {
    return jwt.verify(token, secret, async function (err, decoded) {
        if (err) {
            console.error(err);

            return {
                flag: false,
                msg: err
            }
        }

        console.log('decoded', decoded, typeof decoded);

        const {
            phone,
            upwd
        } = decoded;

        let r = await find('imagepic', 'auth', {
            phone,
            upwd
        });

        console.log('r', r)

        if (r.flag == true) {
            if (JSON.parse(r.data)._collections[0].upwd === decoded.upwd) {
                return {
                    flag: true,
                    msg: '验证成功'
                }
            } else {
                return {
                    flag: false,
                    msg: '登录密码不正确'
                }
            }
        } else {
            return {
                flag: false,
                msg: '登录用户未找到'
            }
        }
    });
}

auth

For login registration verification

const router = require('../../router');
const url = require('url');

const {
  pagination,
  isEmpty,
  isArray,
  PWD_REG,
  NAME_REG,
  EMAIL_REG,
  PHONE_REG
} = require('../../../utils');

const {
  // mongoose,
  cloud_register,
  cloud_login,
  cloud_change,
  signToken
} = require('../../../lib');

// const Schema = mongoose.Schema;


/**
 * @openapi
 * /imagepic/auth/register:
    post:
      summary: 注册
      tags: 
        - listObjects
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/register'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: {}
                msg: "成功"
                success: true
 */
router.post('/register', async function (req, res) {
  const params = req.body;

  console.log('params', params);

  let flag = true,
    err = [];

  const {
    name,
    tfs,
    email,
    phone,
    upwd
  } = params;

  flag = flag && PWD_REG.test(upwd) &&
    EMAIL_REG.test(email) &&
    PHONE_REG.test(phone);

  if (!PWD_REG.test(upwd)) err.push('密码不符合规范');

  if (!EMAIL_REG.test(email)) err.push('邮箱填写不符合规范');

  if (!PHONE_REG.test(phone)) err.push('手机号码填写不符合规范');

  // const registerSchema = new Schema({
  //   name: String,
  //   tfs: String,
  //   email: String,
  //   phone: String,
  //   upwd: String
  // });

  // const Register = mongoose.model('Register', registerSchema);


  if (flag) {
    // const register = new Register({
    //   name,
    //   tfs,
    //   email,
    //   phone,
    //   upwd
    // });



    // register.save().then((result)=>{
    //     console.log("成功的回调", result);

    //     res.json({
    //       code: "0",
    //       data: {},
    //       msg: '成功',
    //       success: true
    //     });
    // },(err)=>{
    //     console.log("失败的回调", err);

    //     res.json({
    //       code: "-1",
    //       data: {
    //         err: err
    //       },
    //       msg: '失败',
    //       success: false
    //     });
    // });

    let r = await cloud_register('imagepic', 'auth', {
      name,
      tfs,
      email,
      phone,
      upwd
    });

    if (r.flag) {
      res.json({
        code: "0",
        data: {},
        msg: '成功',
        success: true
      });
    } else {
      res.json({
        code: "-1",
        data: {
          err: r.msg
        },
        msg: '失败',
        success: false
      });
    }

  } else {
    res.json({
      code: "-1",
      data: {
        err: err.join(',')
      },
      msg: '失败',
      success: false
    })
  }
});


/**
 * @openapi
 * /imagepic/auth/login:
    post:
      summary: 登录
      tags: 
        - listObjects
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/login'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: {token:'xxx'}
                msg: "成功"
                success: true
 */
router.post('/login', async function (req, res) {
  const params = req.body;

  console.log('params', params);

  let flag = true,
    err = [];

  const {
    phone,
    upwd
  } = params;

  flag = flag && PWD_REG.test(upwd) &&
    PHONE_REG.test(phone);

  if (!PWD_REG.test(upwd)) err.push('密码不符合规范');

  if (!PHONE_REG.test(phone)) err.push('手机号码填写不符合规范');

  // const registerSchema = new Schema({
  //   name: String,
  //   tfs: String,
  //   email: String,
  //   phone: String,
  //   upwd: String
  // });

  // const Register = mongoose.model('Register', registerSchema);


  if (flag) {
    // const register = new Register({
    //   name,
    //   tfs,
    //   email,
    //   phone,
    //   upwd
    // });



    // register.save().then((result)=>{
    //     console.log("成功的回调", result);

    //     res.json({
    //       code: "0",
    //       data: {},
    //       msg: '成功',
    //       success: true
    //     });
    // },(err)=>{
    //     console.log("失败的回调", err);

    //     res.json({
    //       code: "-1",
    //       data: {
    //         err: err
    //       },
    //       msg: '失败',
    //       success: false
    //     });
    // });

    let r = await cloud_login('imagepic', 'auth', {
      phone,
      upwd
    });

    if (r.flag) {
      const token = signToken({
        phone,
        upwd
      }, 'imagepic');
      // console.log('token', token)
      res.json({
        code: "0",
        data: {
          token: token
        },
        msg: '成功',
        success: true
      });
    } else {
      res.json({
        code: "-1",
        data: {
          err: r.msg
        },
        msg: '失败',
        success: false
      });
    }

  } else {
    res.json({
      code: "-1",
      data: {
        err: err.join(',')
      },
      msg: '失败',
      success: false
    })
  }
});

/**
 * @openapi
 * /imagepic/auth/change:
    post:
      summary: 修改密码
      tags: 
        - listObjects
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/change'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: {token:'xxx'}
                msg: "成功"
                success: true
 */
router.post('/change', async function (req, res) {
  const params = req.body;

  console.log('params', params);

  let flag = true,
    err = [];

  const {
    phone,
    opwd,
    npwd
  } = params;

  flag = flag && PWD_REG.test(opwd) &&
    PWD_REG.test(npwd) &&
    PHONE_REG.test(phone);

  if (!PWD_REG.test(opwd)) err.push('旧密码不符合规范');

  if (!PWD_REG.test(npwd)) err.push('新密码不符合规范');

  if (!PHONE_REG.test(phone)) err.push('手机号码填写不符合规范');

  if (flag) {
    let r = await cloud_login('imagepic', 'auth', {
      phone: phone,
      upwd: opwd
    });

    if (r.flag) {
      const changeResponse = await cloud_change('imagepic', 'auth', {
        phone: phone,
        upwd: npwd
      });

      if(changeResponse.flag) {
        res.json({
          code: "0",
          data: {},
          msg: '成功',
          success: true
        });
      } else {
        res.json({
          code: "-1",
          data: {
            err: changeResponse.msg
          },
          msg: '失败',
          success: false
        });
      }
    } else {
      res.json({
        code: "-1",
        data: {
          err: r.msg
        },
        msg: '失败',
        success: false
      });
    }

  } else {
    res.json({
      code: "-1",
      data: {
        err: err.join(',')
      },
      msg: '失败',
      success: false
    })
  }
})

module.exports = router;

bucket

Interfaces related to bucket operations

const minio = require('../minio');
const router = require('../../router');
const url = require('url');

const {
    pagination,
    isEmpty,
    isArray
} = require('../../../utils');


/**
 * @openapi
 * /imagepic/bucket/listBuckets:
    summary: 查询所有存储桶
    get:
      parameters:
        - name: pageSize
          name: pageNum
          in: query
          description: user id.
          required: false
      tags: 
        - List
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: [
                    {
                        "name": "5g-fe-file",
                        "creationDate": "2021-06-04T10:01:42.664Z"
                    },
                    {
                        "name": "5g-fe-image",
                        "creationDate": "2021-05-28T01:34:50.375Z"
                    }
                ]
                message: "成功"
                success: true
 */
router.get('/listBuckets', function (req, res) {

    const params = url.parse(req.url, true).query;

    console.log('params', params);

    minio.listBuckets(function (err, buckets) {
        if (err) return console.log(err)
        // console.log('buckets :', buckets);
        res.json({
            code: "0",
            // 分页处理
            data: isEmpty(params) ? 
                buckets : 
                isArray(buckets) ?
                 ( params.pageSize && params.pageNum ) ? 
                 pagination(buckets, params.pageSize, params.pageNum) : 
                 [] : 
                 [],
            msg: '成功',
            success: true
        })
    })
})

module.exports = router;

object

Interface for picture objects

const minio = require('../minio');
const router = require('../../router');
const multer = require('multer');
const path = require('path');
const fs = require('fs');

const {
  pagination
} = require('../../../utils');

const {
  verifyToken
} = require('../../../lib');

/**
 * @openapi
 * /imagepic/object/listObjects:
    get:
      summary: 获取存储桶中的所有对象
      tags: 
        - listObjects
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/listObjects'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: 49000
                msg: "成功"
                success: true
 */
router.post('/listObjects', function (req, res) {
  const params = req.body;

  // console.log('listObjects params', params)

  const {
    bucketName,
    prefix,
    pageSize,
    pageNum
  } = params;

  const stream = minio.listObjects(bucketName, prefix || '', false)

  let flag = false,
    data = [];

  stream.on('data', function (obj) {
    data.push(obj);
    flag = true;
  })

  stream.on('error', function (err) {
    console.log(err)

    data = err;
    flag = false;
  })

  stream.on('end', function (err) {
    if (flag) {
      // 分页处理
      res.json({
        code: "0",
        data: pageNum == -1 ? {
          total: data.length,
          lists: data
        } : {
          total: data.length,
          lists: pagination(data, pageSize || 10, pageNum || 1)
        },
        msg: '成功',
        success: true
      })
    } else {
      res.json({
        code: "-1",
        data: err,
        msg: '失败',
        success: false
      })
    }
  })
})

/**
 * @openapi
 * /imagepic/object/getObject:
    post:
      summary: 下载对象
      tags: 
        - getObject
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/getObject'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: 49000
                msg: "成功"
                success: true
 */
router.post('/getObject', function (req, res) {
  const params = req.body;

  // console.log('statObject params', params)

  const {
    bucketName,
    objectName
  } = params;

  minio.getObject(bucketName, objectName, function (err, dataStream) {
    if (err) {
      return console.log(err)
    }
    let size = 0;

    dataStream.on('data', function (chunk) {
      size += chunk.length
    })
    dataStream.on('end', function () {
      res.json({
        code: "0",
        data: size,
        msg: '成功',
        success: true
      })
    })
    dataStream.on('error', function (err) {
      res.json({
        code: "-1",
        data: err,
        msg: '失败',
        success: false
      })
    })
  })
})

/**
 * @openapi
 * /imagepic/object/statObject:
    post:
      summary: 获取对象元数据
      tags: 
        - statObject
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/statObject'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: {
                    "size": 47900,
                    "metaData": {
                        "content-type": "image/png"
                    },
                    "lastModified": "2021-10-14T07:24:59.000Z",
                    "versionId": null,
                    "etag": "c8a447108f1a3cebe649165b86b7c997"
                }
                msg: "成功"
                success: true
 */
router.post('/statObject', function (req, res) {
  const params = req.body;

  // console.log('statObject params', params)

  const {
    bucketName,
    objectName
  } = params;

  minio.statObject(bucketName, objectName, function (err, stat) {
    if (err) {
      return console.log(err)
    }
    // console.log(stat)

    res.json({
      code: "0",
      data: stat,
      msg: '成功',
      success: true
    })
  })
})

/**
 * @openapi
 * /imagepic/object/presignedGetObject:
    post:
      summary: 获取对象临时连接
      tags: 
        - presignedGetObject
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/presignedGetObject'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: "http://172.24.128.7/epnoss-antd-fe/b-ability-close.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=7RGX0TJQE5OX9BS030X6%2F20211126%2Fdefault%2Fs3%2Faws4_request&X-Amz-Date=20211126T031946Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=27644907283beee2b5d6f468ba793db06cd704e7b3fb1c334f14665e0a8b6ae4"
                msg: "成功"
                success: true
 */
router.post('/presignedGetObject', function (req, res) {
  const params = req.body;

  // console.log('statObject params', params)

  const {
    bucketName,
    objectName,
    expiry
  } = params;

  minio.presignedGetObject(bucketName, objectName, expiry || 7 * 24 * 60 * 60, function (err, presignedUrl) {
    if (err) {
      return console.log(err)
    }
    // console.log(presignedUrl)

    res.json({
      code: "0",
      data: presignedUrl,
      msg: '成功',
      success: true
    })
  })
})

/**
 * @openapi
 * /imagepic/object/putObject:
    post:
      summary: 上传图片
      tags: 
        - putObject
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/putObject'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: ""
                msg: "成功"
                success: true
 */
router.post('/putObject', multer({
  dest: path.resolve(__dirname, '../../../../db/__temp__')
}).single('file'), async function (req, res) {
  console.log('/putObject', req.file, req.headers);
  const verifyResponse = await verifyToken(req.headers.authorization, 'imagepic');

  console.log('verifyResponse', verifyResponse)
  const bucketName = req.headers.bucket,
      folder = req.headers.folder,
      originName = req.file['originalname'],
      file = req.file['path'],
      ext = path.extname(req.file['originalname']),
      fileName = req.file['filename'];
    console.log('folder', folder);

  if (!verifyResponse.flag) {
    fs.unlink(path.resolve(__dirname, `../../../../db/__temp__/${fileName}`), function (err) {
      if (err) {
        console.error(`删除文件 ${fileName} 失败,失败原因:${err}`)
      }
      console.log(`删除文件 ${fileName} 成功`)
    });
    return res.json({
      code: "-1",
      data: verifyResponse.msg,
      msg: '未满足权限',
      success: false
    })
  } else {
    const fullName = folder ? `${folder}/${originName}` : `${originName}`;
    fs.stat(file, function (err, stats) {
      if (err) {
        return console.log(err)
      }
      minio.putObject(bucketName, fullName, fs.createReadStream(file), stats.size, {
        'Content-Type': `image/${ext}`
      }, function (err, etag) {
        fs.unlink(path.resolve(__dirname, `../../../../db/__temp__/${fileName}`), function (err) {
          if (err) {
            console.error(`删除文件 ${fileName} 失败,失败原因:${err}`)
          }
          console.log(`删除文件 ${fileName} 成功`)
        });
        if (err) {
          return res.json({
            code: "-1",
            data: err,
            msg: '失败',
            success: false
          })
        } else {
          return res.json({
            code: "0",
            data: etag,
            msg: '成功',
            success: true
          })
        }
      })
    })
  }
});

/**
 * @openapi
 * /imagepic/object/removeObject:
    post:
      summary: 删除图片
      tags: 
        - removeObject
      requestBody:
        required: true
        content: 
          application/json: 
            schema: 
              $ref: '#/components/schemas/removeObject'
      responses:  
        '200':
          content:
            application/json:
              example:
                code: "0"
                data: ""
                msg: "成功"
                success: true
 */
router.post('/removeObject', async function (req, res) {
  console.log('/removeObject', req.body, req.headers);
  const verifyResponse = await verifyToken(req.headers.authorization, 'imagepic');

  if (!verifyResponse.flag) {
    return res.json({
      code: "-1",
      data: verifyResponse.msg,
      msg: '未满足权限',
      success: false
    })
  } else {
    const {
      bucketName,
      objectName
    } = req.body;
    minio.removeObject(bucketName, objectName, function (err) {
      if (err) {
        return res.json({
          code: "-1",
          data: err,
          msg: '失败',
          success: false
        })
      }
      return res.json({
        code: "0",
        data: {},
        msg: '成功',
        success: true
      })
    })
  }
});

module.exports = router;

Summarize

In the process of developing the back-end interface for the front-end map bed, I really feel the simplicity of using the serverless method for data-side development. For node.js, it may be more applicable to use the faas form for business development with related function granularity. However, for other existing scenarios, it is difficult for node.js to shake the status of traditional back-end languages such as java, go, and c++ in the back-end market. Therefore, I personally think that in some scenarios, such as heavy IO And in the event model-based business, the serverlessization of node.js may become the follow-up development momentum, and the multilingual back-end service form with other heavy computing scenarios may be a form in the future. (ps: The concept of faas is only used here. The real serverless should not only use the format of such a function. More importantly, the scheduling of the baas layer is what the server should pay more attention to. It doesn’t matter whether it is serverless or not, we The main focus should be on services rather than resources)


维李设论
1.1k 声望4k 粉丝

专注大前端领域发展