Suitable for beginners or front-end learning Node. js to do background start tutorial
Content:
- Project construction and configuration
- Back-end request
header
Basic Configuration Description - Interface writing and parameter processing
- To upload pictures
- Link database and interface operations
- Log in to the registered user module
jwt-token
Use of authentication (here I am using a module I wrote myself)- Add delete change check function
- Project builds are pushed online
The reason I’m writing in typescript here is because of the excellent type hints and code tracking, so typescript is best maintained and read in pure javascript projects, and vscode is the code editor used here
Code Address:node-koa
Let’s take a look at the directory structure
public
Template to store static pages such as api-xxx. HTML for front-end interface debugging pages
User. json Temporary table for storing JwT-token data
Upload Temporary directory for storing uploaded files
src
API each interface module, is also a routing directory
Modules Some class function directories
Utils tool directory
Project construction and configuration
1. cd project
And createsrc
directory
mkdir src
Copy the code
2. The initializationpackage.json
All subsequent configurations and commands are written in it
npm init
Copy the code
3. The installationkoa
And the corresponding routekoa-router
npm install koa koa-router
Copy the code
4. InstallTypeScript
Corresponding type detection prompt
npm install --save-dev @types/koa @types/koa-router
Copy the code
5. And then there isTypeScript
Hot update compilation
npm install --save-dev typescript ts-node nodemon
Copy the code
There will be a pit where the ts-Node and Nodemon commands require a global installation to execute hot updates if the installation fails or cannot be executed after installation: like this
npm install -g -force ts-node nodemon
Copy the code
6. Configure it againpackage.json
Set up the
"scripts": {
"start": "tsc && node dist/index.js"."serve": "nodemon --watch src/**/* -e ts,tsx --exec ts-node ./src/index.ts"
},
Copy the code
Nodemon –watch SRC /**/* -e ts, TSX –exec ts-node./ SRC /index.ts
Not sure whetherwindow
The problem with the environment is againnpm
When a project is first created and executed, all dependencies can be installed locally andnpm run serve
You can also perform perfectly but fail when you open the project again. The cause has not been found yet, but the above method can be solved
7. Optional middlewarekoa-body
Middleware is used to parse POST parameters and upload images
npm install koa-body
Copy the code
8. Install the database module and type dependencies
npm install mysql
Copy the code
npm install --save-dev @types/mysql
Copy the code
9. Finally, configure the code parameters
Modules /config.ts project Settings
class ModuleConfig {
/** Port number */
readonly port = 1995;
/** Database configuration */
readonly db = {
host: "localhost".user: "root".password: "root"./** Database name */
database: "node_ts".// This will be the name when the database is created
/** Maximum number of links */
connection_limit: 10
}
/** The interface prefix */
readonly api_prefix = "/api/v1/";
/** Upload the image directory */
readonly upload_path = "public/upload/images/";
/** Upload image size limit */
readonly upload_img_size = 5 * 1024 * 1024;
/** * Specifies the field * used when uploading images@example
* const formData = new FormData()
* formData.append("img", file)
* XHR.send(formData)
*/
readonly upload_img_name = "img";
/** User temporary table */
readonly user_file = "public/user.json";
/** Token length */
readonly token_size = 28;
/** Token format error message */
readonly token_tip = "Invalid token";
}
/** Project configuration */
const config = new ModuleConfig();
export default config;
Copy the code
Back-end requestheader
Basic Configuration Description
In index.ts, part of the interface is token dependent, so I have also written the token check code in this file
jwt-token
I’ll explain the modules later, but I don’t need to bring themtoken
Interface processing of
import * as Koa from "koa"; // learn: https://www.npmjs.com/package/koa
import * as koaBody from "koa-body"; // learn: http://www.ptbird.cn/koa-body.html
import config from "./modules/Config";
import router from "./api/main";
import "./api/apiUser"; // User module
import "./api/apiUpload"; // Upload file module
import "./api/apiTest"; // Basic test module
import "./api/apiTodo"; // User list module
import { TheContext } from "./utils/interfaces";
const App = new Koa();
// Set the request configuration => cross domain, request header information...
App.use(async (ctx: TheContext, next) => {
// ** Request path */
// const path = ctx.request.path;
console.log("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -");
console.count("request count");
ctx.set({
"Access-Control-Allow-Origin": "*".// Specify the request domain, * means that all domain names can be accessed, i.e. open across domains
// "Content-Type": "application/json",
// "Access-Control-Allow-Credentials": "true",
// "Access-Control-Allow-Methods": "OPTIONS, GET, PUT, POST, DELETE",
"Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept, Authorization"./ / "X - Powered By" : "3.2.1,"
// "content-security-policy ": 'script-src "self"' // only allow page 'script' to import its own domain name address
});
// const hasPath = router.stack.some(item => item.path == path);
// // Check whether 404 is displayed
// if (path ! = "/" &&! hasPath) {
// return ctx.body = "
// }
Xhr. setRequestHeader(" content-type ", "application/json")
// ctx.set must carry "access-Control-allow-headers ": "Origin, X-requested-with, content-type, Accept, Authorization"
// If xhr.setrequestheader ("Authorization", "XXXX ") is set, the corresponding field is Authorization
// Change the status code
// console.log(ctx.request.method);
if (ctx.request.method === "OPTIONS") {
ctx.response.status = 200;
}
try {
await next();
} catch (err) {
ctx.response.status = err.statusCode || err.status || 500;
ctx.response.body = {
message: err.message
}
}
});
// Use middleware to handle post parameters and upload images
App.use(koaBody({
multipart: true.formidable: {
maxFileSize: config.uploadImgSize
}
}));
// Start routing
App.use(router.routes())
// There is no routing mode by default
// App.use((ctx, next) => {
// ctx.body = html;
// // console.log(ctx.response);
// });
App.on("error".(err, ctx) = > {
console.error("server error !!!!!!!!!!!!!", err, ctx);
})
App.listen(config.port, () = > {
console.log(`server is running at http://localhost:${ config.port }`);
})
/ / reference project configuration link: https://juejin.im/post/5ce25993f265da1baa1e464f
// mysql learn: https://www.jianshu.com/p/d54e055db5e0
Copy the code
Run the project after you’re done (code hot update)
npm run watch-update
Copy the code
Interface writing and parameter processing
To define a route and export it to use, there may be multiple module interfaces later, so it is all based on this, as is index.ts
The API/main ts file
import * as Router from 'koa-router';
/** API routing module */
const router = new Router();
export default router;
Copy the code
API /apiTest. Ts file, to write a GET and POST request without connecting to the database as a test, and receive parameters, after writing in the front end request, I will not do the description of the front end code, read the comment to understand. After writing to the front page to request whether the correct running can be.
import * as fs from "fs";
import * as path from "path";
import router from "./main";
import utils from ".. /utils";
import { apiSuccess } from ".. /utils/apiResult";
import config from ".. /modules/Config";
/** Resource path */
const resourcePath = path.resolve(__dirname, '.. /.. /public/template');
const template = fs.readFileSync(resourcePath + "/page.html"."utf-8");
// "/*
router.get("/".(ctx, next) = > {
// Specify the return type
// ctx.response.type = "html";
ctx.response.type = "text/html; charset=utf-8";
const data = {
pageTitle: "serve-root".jsLabel: "".content: `<button class="button button_green"><a href="/home">go to home<a></button>`
}
ctx.body = utils.replaceText(template, data);
// console.log(" root ");
// Route redirection
// ctx.redirect("/home");
// Redirect to another website
// ctx.status = 302;
// ctx.redirect("https://www.baidu.com");
})
router.get("/home".(ctx, next) = > {
ctx.response.type = "text/html; charset=utf-8";
const data = {
pageTitle: "serve-root".jsLabel: "".content: `<h1 style="text-align: center; line-height: 40px; font-size: 24px; color: #007fff">Welcome to home</h1>`
}
ctx.body = utils.replaceText(template, data);
// console.log("/home");
})
/ / get request
router.get("/getData".(ctx, next) = > {
/** Receive parameters */
const params: object | string = ctx.query || ctx.querystring;
console.log("/getData", params);
ctx.body = apiSuccess({
method: "get".port: config.port,
date: utils.formatDate()
});
})
/ / post request
router.post("/postData".(ctx, next) = > {
/** Receive parameters */
const params: object = ctx.request.body || ctx.params;
console.log("/postData", params);
const result = {
data: "Request successful"
}
ctx.body = apiSuccess(result, "post success")})Copy the code
To upload pictures
Upload the file to the server
Modules/API/apiupload. ts
import * as fs from "fs";
import * as path from "path";
import router from "./main";
import config from ".. /modules/Config";
import { UploadFile } from ".. /utils/interfaces";
import { apiSuccess } from ".. /utils/apiResult";
// Upload the image
// learn: https://www.cnblogs.com/nicederen/p/10758000.html
// learn: https://blog.csdn.net/qq_24134853/article/details/81745104
router.post("/uploadImg".async (ctx, next) => {
const file: UploadFile = ctx.request.files[config.uploadImgName] as any;
let fileName: string = ctx.request.body.name || `img_The ${Date.now()}`;
fileName = `${fileName}.${file.name.split(".") [1]}`;
// Create a readable stream
const render = fs.createReadStream(file.path);
const filePath = path.join(config.uploadPath, fileName);
const fileDir = path.join(config.uploadPath);
if(! fs.existsSync(fileDir)) { fs.mkdirSync(fileDir); }// Create a write stream
const upStream = fs.createWriteStream(filePath);
render.pipe(upStream);
// console.log(fileName, file);
const result = {
image: `http://${ctx.headers.host}/${config.uploadPath}${fileName}`.file: `${config.uploadPath}${fileName}`
}
ctx.body = apiSuccess(result, "Upload successful");
})
Copy the code
Upload to Aliyun
First install the corresponding SDK, here you can see the document operation, the code is very simple
# module dependency
npm install ali-oss -S
# type package
npm install @types/ali-oss -D
Copy the code
Code snippet
import * as path from "path";
import * as OSS from "ali-oss";
import router from "./main";
import config from ".. /modules/Config";
import { TheContext, UploadFile } from ".. /utils/interfaces";
import { apiSuccess } from ".. /utils/apiResult";
/ * * * -] [ali cloud OSS - API documentation (https://help.aliyun.com/document_detail/32068.html?spm=a2c4g.11186623.6.1074.612626fdu6LBB7) ] - [user management (https://ram.console.aliyun.com/users) * /
const client = new OSS({
// yourregion Fill in the Bucket region. For east China 1 (Hangzhou), set Region to OSS-CN-Hangzhou.
region: "oss-cn-guangzhou".accessKeyId: "Key generated by Ali Cloud Platform".accessKeySecret: "Secret generated backstage by Ali Yunping".bucket: "Specify the name of the bucket to upload"});// Upload the image
// learn: https://www.cnblogs.com/nicederen/p/10758000.html
// learn: https://blog.csdn.net/qq_24134853/article/details/81745104
router.post("/uploadImg".async ctx => {
const file: UploadFile = ctx.request.files[config.uploadImgName] as any;
// console.log("file >>", file);
let fileName: string = `The ${Math.random().toString(36).slice(2)}-The ${Date.now()}-${file.name}`;
const result = await client.put(`images/${fileName}`, path.normalize(file.path));
// console.log(" Upload file result >>", result);
ctx.body = apiSuccess(result, "Upload successful");
})
Copy the code
jwt-token
(here I am using a module written by myself)
Realization idea: usejs
Memory for reading and writing userstoken
Messages are only written to memory (asynchronous write to prevent blocking)json
Format write touser.json
File, and then read the last record when instantiatingtoken
Information and get rid of the outdated ones. It can be used when writing or readingRedis
Instead of reading and writing locallyuser.json
Table, the principle is the same.
Implementation process:
-
Create a new user.json file in the public/ directory as a temporary token record table
-
Then define a ModuleJWT module. The private userRecord is a token-based object that stores user information. This information contains a parameter online meaning the time that the user is online, which will be used to determine the value later
-
Only three methods are exposed in the ModuleJWT module:
-
SetRecord sets the record for the first time and returns the token login, and the record is in the userRecord, and then written to the temporary table user.json.
-
UserRecord [token]. Online; userRecord[token]. Online; Update userRecord[token]. Online to the current time, and finally write to the temporary table. This process can be complicated, so it’s better to look at the code.
-
RemoveRecord removes the current token from userRecord
-
-
When the ModuleJWT is instantiated, it first reads the last written information from the user.json temporary table and then removes outdated tokens to ensure data synchronization.
-
Finally, in the process of running the code, periodically remove outdated tokens to reduce the performance of read/write and memory size, depending on the code.
Under the modules/Jwt. Ts file
import * as fs from "fs";
import config from "./Config";
import { apiSuccess } from ".. /utils/apiResult";
import {
UserRecordType,
UserInfoType,
JwtResultType,
TheContext,
ApiResult
} from ".. /utils/interfaces";
/ * * * custom ` JWT - token ` authentication module, different from [koa - JWT] * (https://www.npmjs.com/package/koa-jwt)@author [Hjs](https://github.com/Hansen-hjs)
*/
class ModuleJWT {
constructor() {
this.init();
}
/** Validity period (hours) */
private maxAge = 12;
/** Update & test interval (10 minutes) */
private interval = 600000;
/** User 'token' record */
private userRecord: UserRecordType = {};
/** * write file *@param Obj The object to write to */
private write(obj? : UserRecordType) {
const data = obj || this.userRecord;
// Synchronous write (not necessary)
// fs.writeFileSync(config.userFile, JSON.stringify(data), { encoding: "utf8" });
// Write asynchronously
fs.writeFile(config.userFile, JSON.stringify(data), { encoding: "utf8" }, err= > {
if (err) {
console.log('\x1B[41m jwt-token write failed \x1B[0m', err);
} else {
console.log('\x1B[42m jwt-token Write succeeded \x1B[0m'); }})}/** Initialize user state from local temporary table */
private init() {
// fs.accessSync(config.userFile)
if(! fs.existsSync(config.userFile)) {console.log(`\x1B[42m ${config.userFile}It does not exist. Start creating the file);
fs.writeFileSync(config.userFile, "{}", { encoding: "utf8" });
}
const userFrom = fs.readFileSync(config.userFile).toString();
this.userRecord = userFrom ? JSON.parse(userFrom) : {};
this.checkRecord();
// console.log("token temporary table ", userFrom, this.userRecord);
}
/** Generate 'token' */
private getToken() {
const getCode = (n: number) :string= > {
let codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789";
let code = "";
for (let i = 0; i < n; i++) {
code += codes.charAt(Math.floor(Math.random() * codes.length));
}
if (this.userRecord[code]) {
return getCode(n);
}
return code;
}
const code = getCode(config.tokenSize);
return code;
}
/** Periodically detect expired 'tokens' and clean up */
private checkRecord() {
const check = () = > {
const now = Date.now();
let isChange = false;
for (const key in this.userRecord) {
if (this.userRecord.hasOwnProperty(key)) {
const item = this.userRecord[key];
if (now - item.online > this.maxAge * 3600000) {
isChange = true;
delete this.userRecord[key]; }}}if (isChange) {
this.write(); }}// Time check
setInterval(check, this.interval);
check();
}
/** * sets record and returns' token '*@param Data User information */
setRecord(data: UserInfoType) {
const token = this.getToken();
data.online = Date.now();
this.userRecord[token] = data;
this.write();
return token;
}
/** * Update and test 'token' *@param token
* @description Here you can do single sign-on processing, modify the rules to judge can */
updateRecord(token: string) {
const result: JwtResultType = {
message: "".success: false.info: null
}
if (!this.userRecord.hasOwnProperty(token)) {
result.message = "Token has expired or does not exist";
return result;
}
const userInfo = this.userRecord[token];
const now = Date.now();
if (now - userInfo.online > this.maxAge * 3600000) {
result.message = "Token has expired";
return result;
}
result.message = "Token verified";
result.success = true;
result.info = userInfo;
// Update online time and write to temporary table
// The write and update interval is 10 minutes to avoid frequent writes
if (now - userInfo.online > this.interval) {
this.userRecord[token].online = now;
this.write();
}
return result;
}
/** * delete 'token' from record *@param token
* @description */ is used to log out
removeRecord(token: string) {
if (this.userRecord.hasOwnProperty(token)) {
delete this.userRecord[token];
this.write();
return true;
} else {
return false; }}/** * Check the status of the interface that requires' token '*@param context
*/
checkToken(context: TheContext) {
const token: string = context.header.authorization;
let fail = false;
let info: ApiResult;
if(! token) { fail =true;
info = apiSuccess({}, "Lack of token".400);
}
if(token && token.length ! = config.tokenSize) { fail =true;
info = apiSuccess({}, config.tokenTip, 400);
}
const state = this.updateRecord(token);
if(! state.success) { fail =true;
info = apiSuccess({}, state.message, 401);
}
// Set the token information to the context for the interface module to call
if(! fail) { context["theState"] = state;
}
return {
fail,
info
}
}
}
/** 'jwt-token' module */
const jwt = new ModuleJWT();
export default jwt;
Copy the code
Connect database and interface operations
The local service I use here is set up with (Upupw), super simple operation, database table tool is Navicat
Upupw download address
Navicat download address online crack is also a lot, you can download yourself
-
Here, use the upupw command window to obtain the account password of the data and create a new database connection in Navicat. Fill in the password according to the account. Do not change the default port, otherwise the connection will fail.
-
Create a new database named node_ts in the left column. Config.db. database is the same as this column.
- Start building one called
user_form
The table of
Do not want to build a table can be directly to the projectmysql/node_ts.sql
File to importnode_ts
Database
SRC /utils/mysql.ts: SRC /utils/mysql.ts: SRC /utils/mysql.ts: SRC /utils/mysql.ts: SRC /utils/mysql.ts: SRC /utils/mysql.ts: SRC /utils/mysql.ts: SRC /utils/mysql.ts
import * as mysql from "mysql"; // learn: https://www.npmjs.com/package/mysql
import config from ".. /modules/Config";
interface queryResult {
/** 'state===1' */
state: number
/** Result array or object */
results: any
/** 状态 */
fields: Array<mysql.FieldInfo>
/** Error message */
error: mysql.MysqlError
/** Description */
msg: string
}
/** database */
const pool = mysql.createPool({
host: config.db.host,
user: config.db.user,
password: config.db.password,
database: config.db.database
});
/** * add/delete **@param Command adds, deletes, and checks statements *@param Value Indicates the corresponding value */
export default function query(command: string, value? :Array<any>) {
const result: queryResult = {
state: 0.results: null.fields: null.error: null.msg: ""
}
return new Promise<queryResult>((resolve, reject) = > {
pool.getConnection((error: any, connection) = > {
if (error) {
result.error = error;
result.msg = "Database connection error";
resolve(result);
} else {
const callback: mysql.queryCallback = (error: any, results, fields) = > {
// pool.end();
connection.release();
if (error) {
result.error = error;
result.msg = "Error detected in database addition, deletion and modification.";
resolve(result);
} else {
result.state = 1;
result.msg = "ok"; result.results = results; result.fields = fields; resolve(result); }}if (value) {
pool.query(command, value, callback);
} else{ pool.query(command, callback); }}}); }); }// learn: https://blog.csdn.net/gymaisyl/article/details/84777139
Copy the code
Log in to the registered user module
Mysql query statements correspond to user_Form table fields
Under the SRC/API/apiUser ts file
import router from "./main";
import query from ".. /utils/mysql";
import jwt from ".. /modules/Jwt";
import config from ".. /modules/Config";
import {
UserInfoType,
TheContext,
ApiResult
} from ".. /utils/interfaces";
import { apiSuccess, apiFail } from ".. /utils/apiResult";
/ / register
router.post("/register".async (ctx) => {
/** Receive parameters */
const params: UserInfoType = ctx.request.body;
/** Returns the result */
let bodyResult: ApiResult;
/** Whether the account is available */
let validAccount = false;
// console.log(" register to pass parameters ", params);
if (!/^[A-Za-z0-9]+$/.test(params.account)) {
return ctx.body = apiSuccess({}, "Registration failed! Account number must be in English or numerals.".400);
}
if (!/^[A-Za-z0-9]+$/.test(params.password)) {
return ctx.body = apiSuccess({}, "Registration failed! Passwords must be in English or numerals.".400);
}
if(! params.name.trim()) { params.name ="User does not set a nickname";
}
// Check whether there are duplicate accounts
const res = await query(`select account from user_form where account='${ params.account }'`)
// console.log(" register query ", res);
if (res.state === 1) {
if (res.results.length > 0) {
bodyResult = apiSuccess({}, "The account has been registered.".400);
} else {
validAccount = true; }}else {
ctx.response.status = 500;
bodyResult = apiFail(res.msg, 500, res.error);
}
// Write the table again
if (validAccount) {
const res = await query("insert into user_form(account, password, username) values(? ,? ,?) ", [params.account, params.password, params.name])
if (res.state === 1) {
bodyResult = apiSuccess(params, "Registration successful");
} else {
ctx.response.status = 500;
bodyResult = apiFail(res.msg, 500, res.error);
}
}
ctx.body = bodyResult;
})
/ / login
router.post("/login".async (ctx) => {
/** Receive parameters */
const params: UserInfoType = ctx.request.body;
/** Returns the result */
let bodyResult: ApiResult;
// console.log(" login ", params);
if(! params.account || params.account.trim() ==="") {
return ctx.body = apiSuccess({}, "Login failed! Account cannot be empty".400);
}
if(! params.password || params.password.trim() ==="") {
return ctx.body = apiSuccess({}, "Login failed! Password cannot be empty".400);
}
// Check whether the current account exists
const res = await query(`select * from user_form where account = "${ params.account }"`)
console.log("Login Query", res);
if (res.state === 1) {
// Check whether the account is available
if (res.results.length > 0) {
const data: UserInfoType = res.results[0];
// Check whether the password is correct
if (data.password == params.password) {
data.token = jwt.setRecord({
id: data.id,
account: data.account,
password: data.password
});
bodyResult = apiSuccess(data ,"Login successful");
} else {
bodyResult = apiSuccess({}, "Incorrect password".400); }}else {
bodyResult = apiSuccess({}, "This account does not exist, please register first.".400); }}else {
ctx.response.status = 500;
bodyResult = apiFail(res.msg, 500, res.error);
}
ctx.body = bodyResult;
})
// Get user information
router.get("/getUserInfo".async (ctx: TheContext) => {
const checkInfo = jwt.checkToken(ctx);
if (checkInfo.fail) {
return ctx.body = checkInfo.info;
}
const state = ctx["theState"];
// ** Receive parameters */
// const params = ctx.request.body;
/** Returns the result */
let bodyResult: ApiResult;
// console.log("getUserInfo", params, state);
const res = await query(`select * from user_form where account = "${ state.info.account }"`)
if (res.state === 1) {
// Check whether the account is available
if (res.results.length > 0) {
const data: UserInfoType = res.results[0];
bodyResult = apiSuccess(data);
} else {
bodyResult = apiSuccess({}, "The account does not exist and may have been deleted from the database.".400); }}else {
ctx.response.status = 500;
bodyResult = apiFail(res.msg, 500, res.error);
}
ctx.body = bodyResult;
})
// Log out
router.get("/logout".ctx= > {
const checkInfo = jwt.checkToken(ctx);
if (checkInfo.fail) {
return ctx.body = checkInfo.info;
}
const token: string = ctx.header.authorization;
/** Receive parameters */
const params = ctx.request.body;
console.log("logout", params, token);
if(token.length ! = config.tokenSize) {return ctx.body = apiSuccess({}, config.tokenTip);
}
const state = jwt.removeRecord(token);
if (state) {
return ctx.body = apiSuccess({}, "Logged out successfully");
} else {
return ctx.body = apiSuccess({}, "Token does not exist".400); }})Copy the code
Add delete change check function
Then create a table called todo_form
Finally, create a new apitodo. ts interface module to add, delete, modify and check the user list
import router from './main';
import query from '.. /modules/mysql';
import stateInfo from '.. /modules/state';
import { mysqlQueryType, mysqlErrorType, JwtResultType } from '.. /modules/interfaces';
// Get all the lists
router.get('/getList'.async (ctx) => {
const checkInfo = jwt.checkToken(ctx);
if (checkInfo.fail) {
return ctx.body = checkInfo.info;
}
const state: JwtResultType = ctx['theState'];
/** Returns the result */
let bodyResult = null;
// console.log('getList');
// start table query
await query(`select * from todo_form where user_id = '${ state.info.id }'`).then((res: mysqlQueryType) = > {
// console.log('/getList query ', res.results);
bodyResult = stateInfo.getSuccessData({
list: res.results.length > 0 ? res.results : []
});
}).catch((err: mysqlErrorType) = > {
bodyResult = stateInfo.getFailData(err.message);
})
ctx.body = bodyResult;
})
// Add a list
router.post('/addList'.async (ctx) => {
const checkInfo = jwt.checkToken(ctx);
if (checkInfo.fail) {
return ctx.body = checkInfo.info;
}
const state: JwtResultType = ctx['theState'];
/** Receive parameters */
const params = ctx.request.body;
/** Returns the result */
let bodyResult = null;
if(! params.content) {return ctx.body = stateInfo.getFailData('Add list contents cannot be empty! ');
}
// Write the list
await query('insert into todo_form(content, time, user_id) values(? ,? ,?) ', [params.content, new Date().toLocaleDateString(), state.info.id]).then((res: mysqlQueryType) = > {
// console.log(' write list ', res.results.insertid);
bodyResult = stateInfo.getSuccessData({
id: res.results.insertId
}, 'Added successfully');
}).catch((err: mysqlErrorType) = > {
// console.log(' register write error ', err);
bodyResult = stateInfo.getFailData(err.message);
})
ctx.body = bodyResult;
})
// Modify the list
router.post('/modifyList'.async (ctx) => {
const checkInfo = jwt.checkToken(ctx);
if (checkInfo.fail) {
return ctx.body = checkInfo.info;
}
const state: JwtResultType = ctx['theState'];
/** Receive parameters */
const params = ctx.request.body;
/** Returns the result */
let bodyResult = null;
if(! params.id) {return ctx.body = stateInfo.getFailData('List ID cannot be empty');
}
if(! params.content) {return ctx.body = stateInfo.getFailData('List contents cannot be empty');
}
// Modify the list
await query(`update todo_form set content='${params.content}', time='The ${new Date().toLocaleDateString()}' where list_id='${params.id}'`).then((res: mysqlQueryType) = > {
console.log('Change list', res);
if (res.results.affectedRows > 0) {
bodyResult = stateInfo.getSuccessData({}, 'Modified successfully');
} else {
bodyResult = stateInfo.getFailData('List ID does not exist');
}
}).catch((err: mysqlErrorType) = > {
// console.log(' register write error ', err);
bodyResult = stateInfo.getFailData(err.message);
})
ctx.body = bodyResult;
})
// Delete the list
router.post('/deleteList'.async (ctx) => {
const checkInfo = jwt.checkToken(ctx);
if (checkInfo.fail) {
return ctx.body = checkInfo.info;
}
const state: JwtResultType = ctx['theState'];
/** Receive parameters */
const params = ctx.request.body;
/** Returns the result */
let bodyResult = null;
// Delete from the database
await query(`delete from todo_form where list_id=${params.id} and user_id = ${state.info.id}`).then((res: mysqlQueryType) = > {
console.log('Delete from database', res);
if (res.results.affectedRows > 0) {
bodyResult = stateInfo.getSuccessData({}, 'Deleted successfully');
} else {
bodyResult = stateInfo.getFailData('Current list ID does not exist or deleted');
}
}).catch((err: mysqlErrorType) = > {
console.log('Delete from database failed', err);
bodyResult = stateInfo.getFailData(err.message);
})
ctx.body = bodyResult;
})
Copy the code
Back-end request third-party Interface (advanced)
- This is a
node.js
One of the core functions, in principle andKoa
Have nothing to do with; Because the Internet can search the relevant information is less, so here incidentally also bring - This function is mainly some time we need to get some data from the third party, and then return to the front end, similar to wechat small program back-end interface will be used, here is not an example
Create a new request.ts file in the utils directory
import * as http from "http";
import * as querystring from "querystring"
import * as zlib from "zlib"
import { ServeRequestResult } from "./interfaces";
/ * * * * server request - based request reference [] (https://www.cnblogs.com/liAnran/p/9799296.html) * - The code reference] [response result * - (https://blog.csdn.net/fengxiaoxiao_1/article/details/72629577) Garbled reference [HTML] * - (https://www.microanswer.cn/blog/51) [] node - HTTP document * (http://nodejs.cn/api/http.html#http_class_http_incomingmessage)@param Options Request configuration *@param Params requests to send data */
export default function request(options: http.RequestOptions, params: object = {}) :Promise<ServeRequestResult> {
/** Returns the result */
const info: ServeRequestResult = {
msg: "".result: "".state: -1
}
/** Pass the parameter field */
const data = querystring.stringify(params as any);
if (data && options.method == "GET") {
options.path += `?${data}`;
}
return new Promise((resolve, reject) = > {
const clientRequest = http.request(options, res= > {
// console.log("http.get >>", res);
console.log(`http.request.statusCode: ${res.statusCode}`);
console.log(`http.request.headers: The ${JSON.stringify(res.headers)}`);
// The code is not set because it is now decoding itself.
// res.setEncoding("utf-8");
if(res.statusCode ! = =200) {
info.msg = "Request failed";
info.result = {
statusCode: res.statusCode,
headers: res.headers
}
return resolve(info);
}
let output: http.IncomingMessage | zlib.Gunzip
if (res.headers["content-encoding"] = ="gzip") {
const gzip = zlib.createGunzip();
res.pipe(gzip);
output = gzip;
} else {
output = res;
}
output.on("data".function(chunk) {
console.log("----------> chunk >>");
// info.result += chunk;
// info.result = chunk;
info.result += chunk.toString();
});
output.on("error".function(error) {
console.log("----------> Server request error >>", error);
info.msg = error.message;
info.result = error;
})
output.on("end".function() {
console.log("---------- end ----------");
if (res.complete) {
info.msg = "ok";
info.state = 1;
resolve(info);
} else {
info.msg = "Disconnection"resolve(info); }}); })if(data && options.method ! ="GET") {
clientRequest.write(data)
}
clientRequest.end()
})
}
Copy the code
Here is the weather forecast interface as a demonstration, to request some unique interface, such as data mining such as set up your own headers simulation
import { apiSuccess, apiFail } from ".. /utils/apiResult";
import request from ".. /utils/request";
// Request the third-party interface and return the data to the front end
router.get("/getWeather".async (ctx, next) => {
console.log("ctx.query >>", ctx.query);
if(! ctx.query.city) { ctx.body = apiSuccess({},"Missing field city".400);
return;
}
const res = await request({
method: "GET".hostname: "wthrcdn.etouch.cn".path: "/weather_mini? city=" + encodeURIComponent(ctx.query.city),
// headers: {
// "xxx": "asfdfewf"
// }
})
// console.log(" Get weather info >>", res);
if (res.state === 1) {
if (utils.checkType(res.result) === "string") {
res.result = JSON.parse(res.result);
}
ctx.body = apiSuccess(res.result)
} else {
ctx.body = apiFail(res.msg, 500, res.result)
}
})
Copy the code
Project builds are pushed online
- Buy cloud server ECS Tencent Ali at will;
- Install the corresponding
node.js
,myql
,git
And other tools, in essence with the new computer installed tools, but the server isLinux
The system, operating with the help ofMobaXtermThis tool is used for remote connection, installation and other operations, which do not need to write code. - Create a directory and use
git
Pull the code down,npm install
Run againnpm run start
It is ok, but it is found that the service is shut down after exiting, so it needs to install another process managementpm2Instead of us going manuallynpm run start
; - installed
pm2
Then you need to write one in the current project directorypm2.json
Configuration run file, similarpackage.json
Again, the code snippet is as follows:
{
"name": "node-serve".// The process name
"script": "npm run start" // The command to run the code
}
Copy the code
Finally, execute the pm2 start pm2. Json command to start the project, see the following command for more information
# Start task
pm2 start pm2.json
# Force all services to stop
pm2 kill
# Check service
pm2 list
0 is the index value of the task list
pm2 log 0
Restart the specified process. 0 is the task list index
pm2 restart 0
# stop the specified process. 0 is the task list index
pm2 stop 0
Copy the code
The last show
All front-end debugging of the project is written. Front-end interface code is stored under public/template. Because it is shared with back-end code, there is no front-end code demonstration here.