{"id":26187476,"url":"https://github.com/localsummer/koa2-ts-weibo-api","last_synced_at":"2026-04-09T21:11:14.375Z","repository":{"id":40761760,"uuid":"277110710","full_name":"localSummer/koa2-ts-weibo-api","owner":"localSummer","description":"koa2 + typescript 开发 weibo api","archived":false,"fork":false,"pushed_at":"2023-01-06T10:37:10.000Z","size":898,"stargazers_count":0,"open_issues_count":23,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-03-02T16:35:44.402Z","etag":null,"topics":["jest","jsonwebtoken","koa2","log4js","mysql","pm2","redis","sequelize-orm","typescript"],"latest_commit_sha":null,"homepage":"https://github.com/localSummer/koa2-ts-weibo-api","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/localSummer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-04T13:01:23.000Z","updated_at":"2023-03-02T16:35:44.403Z","dependencies_parsed_at":"2023-02-05T21:46:58.925Z","dependency_job_id":null,"html_url":"https://github.com/localSummer/koa2-ts-weibo-api","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localSummer%2Fkoa2-ts-weibo-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localSummer%2Fkoa2-ts-weibo-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localSummer%2Fkoa2-ts-weibo-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/localSummer%2Fkoa2-ts-weibo-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/localSummer","download_url":"https://codeload.github.com/localSummer/koa2-ts-weibo-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243130997,"owners_count":20241177,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["jest","jsonwebtoken","koa2","log4js","mysql","pm2","redis","sequelize-orm","typescript"],"created_at":"2025-03-11T23:50:01.979Z","updated_at":"2025-12-24T21:19:40.726Z","avatar_url":"https://github.com/localSummer.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"### 技术栈\nkoa2 + typescript + sequelize + sequelize-cli + mysql + redis + jest + log4js + pm2 + gulp\n\n### 功能支持\n1. typescript\n2. sequelize orm\n3. redis 登录token存储\n4. log4js 日志处理\n5. @koa/multer 文件上传\n6. schema-typed 请求参数校验\n7. ctx 自定义属性（及类型）扩展，如 `ctx.success` `ctx.error` `ctx.logger` [koa2+ts中为Context扩展自定义属性](https://blog.csdn.net/roamingcode/article/details/107084933)\n8. jest 测试\n\n\u003e 注意：所有自定义中间件在 `next` 调用时，需使用右侧格式 `await next()`，否则在 `controller` 中操作数据库会引发 `ctx.body` 数据丢失问题\n\n\u003e 本项目对应 `dev` `test` `prd` 三套环境，分别对应于 `config/db.json` 中三套数据库配置\n\n### 数据库操作（命令行操作 或 npm scripts）\n1. `npx sequelize db:create --charset \"utf8mb4\" --collate \"utf8mb4_general_ci\"` 同步数据库\n2. `npx sequelize db:migrate` 同步表\n\n### 项目启动\n#### dev 模式\n1. `npm run compile` 编译后 nodemon 重启服务 或 `gulp-compile` 编译后延迟 `200ms（可配置）` nodemon 重启服务\n2. `npm run dev`\n\n#### prd模式\n1. `npm run build` 打包但代码未进行压缩 或 `npm run gulp-build`  打包并压缩\n2. `npm run prd`\n\n#### scripts\n```javascript\n\"scripts\": {\n  \"compile\": \"tsc --project tsconfig.json -w\",\n  \"dev\": \"cross-env NODE_ENV=development nodemon bin/www\",\n  \"build\": \"tsc --project tsconfig.json\",\n  \"test\": \"cross-env NODE_ENV=test nodemon bin/www\",\n  \"prd\": \"cross-env NODE_ENV=production pm2 start bin/www\",\n  \"clear\": \"rm -r dist\",\n  \"eslint\": \"eslint src --ext .ts\",\n  \"gulp-compile\": \"gulp dev\",\n  \"gulp-build\": \"gulp build\",\n  \"jest\": \"cross-env NODE_ENV=test jest --passWithNoTests --updateSnapshot\",\n  \"jest:watch\": \"cross-env NODE_ENV=test jest --coverage --watch\",\n  \"jest:prod\": \"cross-env NODE_ENV=test npm run jest -- --no-cache\",\n  \"db-create-dev\": \"sequelize db:create --env=development --charset=utf8mb4 --collate=utf8mb4_general_ci\",\n  \"db-migrate-dev\": \"sequelize db:migrate --env=development\",\n  \"db-create-test\": \"sequelize db:create --env=test --charset=utf8mb4 --collate=utf8mb4_general_ci\",\n  \"db-migrate-test\": \"sequelize db:migrate --env=test\",\n  \"db-create-prd\": \"sequelize db:create --env=production --charset=utf8mb4 --collate=utf8mb4_general_ci\",\n  \"db-migrate-prd\": \"sequelize db:migrate --env=production\"\n},\n```\n\n#### 坑点\n```javascript\n// 需要为 Router 添加类型声明，否则 router.post('/delete', UserController.delete); 该接口会报出 ctx 类型不匹配问题\nimport { DefaultState, Context } from 'koa';\nconst router = new Router\u003cDefaultState, Context\u003e();\n```\n\n#### 目录结构\n```\n|-- koa2-ts\n    |-- .eslintignore\n    |-- .eslintrc.js\n    |-- .gitignore\n    |-- .sequelizerc\n    |-- LICENCE\n    |-- README.md\n    |-- gulpfile.js\n    |-- jest.config.js\n    |-- package-lock.json\n    |-- package.json\n    |-- prettier.config.js\n    |-- tsconfig.json\n    |-- bin\n    |   |-- www\n    |-- config\n    |   |-- constant.js\n    |   |-- db.json\n    |   |-- jest\n    |       |-- cssTransform.js\n    |       |-- fileTransform.js\n    |-- coverage\n    |-- db\n    |   |-- migrations\n    |   |   |-- 20200702123744-create-user.js\n    |   |-- seeders\n    |-- dist\n    |-- logs\n    |   |-- access.log.-2020-07-04.log\n    |   |-- application.log.-2020-07-04.log\n    |-- public\n    |   |-- style.css\n    |-- src\n    |   |-- app.ts\n    |   |-- global.d.ts\n    |   |-- __test__\n    |   |   |-- format.test.ts\n    |   |-- controllers\n    |   |   |-- userController.ts\n    |   |-- middlewares\n    |   |   |-- logger.ts\n    |   |   |-- response.ts\n    |   |   |-- upload.ts\n    |   |   |-- validator.ts\n    |   |-- models\n    |   |   |-- connection.ts\n    |   |   |-- index.ts\n    |   |   |-- user.ts\n    |   |-- routes\n    |   |   |-- index.ts\n    |   |-- rules\n    |   |   |-- login.ts\n    |   |-- services\n    |   |   |-- userService.ts\n    |   |-- types\n    |   |   |-- index.ts\n    |   |-- utils\n    |       |-- helper.ts\n    |       |-- log4.ts\n    |-- uploads\n        |-- 2020-07-04\n            |-- 1593850667585.jpg\n```\n\n#### app.ts\n\n```javascript\nimport Koa from 'koa';\nimport onerror from 'koa-onerror';\nimport cors from 'koa2-cors';\nimport bodyparser from 'koa-bodyparser';\nimport json from 'koa-json';\nimport koaLogger from 'koa-logger';\nimport koaStatic from 'koa-static';\nimport path from 'path';\n\nimport koaResponse from './middlewares/response';\nimport logger from './middlewares/logger';\nimport { systemLogger, defaultLogger, accessLogger } from './utils/log4';\nimport index from './routes';\nimport Helper from './utils/helper';\n\nconst app = new Koa();\n\n// 错误处理\nonerror(app);\n\n// 中间件\napp.use(cors());\napp.use(\n  bodyparser({\n    enableTypes: ['json', 'form', 'text']\n  })\n);\napp.use(json());\napp.use(koaLogger());\n// 公共资源访问\napp.use(koaStatic(path.resolve(__dirname, '../public')));\n// 用户上传资源访问\napp.use(koaStatic(path.resolve(__dirname, '../uploads')));\n\n// logger 控制台请求输出\napp.use(async (ctx, next) =\u003e {\n  const start = Date.now();\n  await next();\n  const ms = Date.now() - start;\n  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);\n  accessLogger.info(Helper.logFormat(ctx, ms));\n});\n\n// 自定义控制台输出日志\napp.use(logger(defaultLogger));\napp.use(koaResponse);\n\n// 路由\napp.use(index.routes());\napp.use(index.allowedMethods());\n\n// error-handling\napp.on('error', (err: Error, ctx: Koa.Context) =\u003e {\n  console.error('server error', err, ctx);\n  // 系统日志输出到文件\n  systemLogger.error(err);\n});\n\nexport default app;\n\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocalsummer%2Fkoa2-ts-weibo-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocalsummer%2Fkoa2-ts-weibo-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocalsummer%2Fkoa2-ts-weibo-api/lists"}