preface
In the previous part, we have introduced the modules of project process design, database construction, JWT login and so on.
In this article we introduce branch management design and other basic modules.
The backend module
- DevOps – Gitlab Api usage (completed, click to jump)
- DevOps – Build DevOps base platform (50% completed) Click to jump to the base platform
- DevOps – Gitlab CI pipeline construction
- Devops-jenkins pipelined construction
- Devops-docker use
- DevOps – Release task flow design
- DevOps – Code review points
- Devops-node monitors service quality
The above series may be adjusted later based on the actual development progress of the DevOps project
Git branch management process
Git Flow process
Production branch
This branch can only be merged from other branches and cannot be modified directly in this branch
Develop branch
This branch is the main development branch and contains all the code to be released to the next Release. This branch is mainly merged with other branches, such as the Feature branch
Feature branch
This branch is primarily used to Develop a new feature, and once that’s done, we merge back into the Develop branch and go to the next Release
The Release branch
When a new Release needs to be released, a Release branch is created based on the Develop branch and merged into the Master and Develop branches once the Release is complete
Hotfix branch
When Production discovers a new Bu G, a Hotfix needs to be created. After the Hotfix is completed, it is merged back into the Master and Develop branches, so changes to the Hotfix go to the next Release
The overall branch management process is shown in the figure below
Project self-built process
The above Git Flow process can standardize and constrain the development quality and process. Let’s modify part of the process slightly and integrate it into the project.
As shown in the figure, each project shares a version number. Branch creation can be divided into three modes: version upgrade, feature update, and patch revision. The naming rules for all branches of the project will be upgraded without repetition and degradation.
Advantages of the above process:
- The project is locked with a fixed version. The version corresponds to the demand process and the quality of on-line is guaranteed
- Each development branch can only be deployed to the test environment and must be merged into the corresponding version branch before it can go into production
- All branches merged into master or Relase will be deleted to prevent one branch from processing too many services, making it difficult to review and roll back later
- After the realSE version branch is online, the corresponding tag is generated
- The hotfix version can be pulled out from the corresponding tag, and you can clearly know which version of the hotfix problem is fixed
Disadvantages of the above process:
- The version creation rule is fixed, and the version cannot be upgraded but can only be degraded
- Process constraints reduce development flexibility
There is no perfect solution, all Devops processes need to be designed according to the needs of real projects. The above is just one solution, please add my wechat Cookieboty for more general solution design
DevOps Development Chapter
Add global error callback
There is no absolutely safe program, all programs in the run due to various circumstances will appear error, global error callback is necessary for the base module.
export default class HttpExceptions extends Error { // Inherit to modify the error type
code: number;
msg: string;
httpCode: number;
constructor({ msg = "Server exception", code = 1, httpCode = 400 }) {
super(a);this.msg = msg;
this.code = code;
this.httpCode = httpCode; }}import HttpExceptions from ".. /exceptions/http_exceptions"; // Global intercept error handling
export default() = > {return async function errorHandler(ctx, next) {
try {
await next();
} catch (err) {
// All exceptions raise an error event on the app, and the framework logs an error
ctx.app.emit("error", err, ctx);
let status = err.status || 500;
let error: any = {};
if (err instanceof HttpExceptions) {
status = err.httpCode;
error.requestUrl = `${ctx.method} : ${ctx.path}`;
error.msg = err.msg;
error.code = err.code;
error.httpCode = err.httpCode;
} else {
// Unknown exception, system exception, no stack information displayed online
// The details of the 500 error in production are not returned to the client because they may contain sensitive information
error.code = 500;
error.errsInfo =
status === 500 && ctx.app.config.env === "prod"
? "Internal Server Error"
: err.message;
}
// Read each property from the error object and set it into the response
ctx.body = error;
if (status === 422) { ctx.body.detail = err.errors; } ctx.status = status; }}; };Copy the code
As mentioned above, we expand the default error class and add error middleware to intercept global exceptions. If a custom exception is thrown, the global exception will be processed; otherwise, 500 errors will be thrown to remove sensitive information.
Use the webSocket
Why use webSocket
In project management, it will involve multi-person cooperative operation of the same project, and Ajax rotation training not only consumes performance, but also cannot fully guarantee real-time performance, and will push a lot of invalid information. Therefore, the project adopts Websocket to push the information of multi-person collaboration and the status push of the later construction process.
egg-socket
The framework provides the egg-socket. IO plug-in, which adds the following development specifications:
- Namespace: Define a namespace (namespace) by configuration.
- Middleware: Preprocesses every socket connection setup/disconnect, and every message/data transfer
- Controller: indicates the event that responds to socket. IO
- Router: unified socket. IO event and frame route processing configuration.
For details, see egg-socket. IO. The following is a brief description of ts configuration
import { Application } from "egg"; // Indicates the IO route usage
import { EggShell } from "egg-shell-decorators";
export default (app: Application) => {
const { router, controller, io } = app;
EggShell(app);
// socket.io
io.of('/').route('server', io.controller.nsp.ping);
};
Copy the code
The IO. Controller. NSP report type is undefined in ts usage, so you need to modify the typings/index.d.ts file.
import "egg";
declare module "egg" {
interface Application { }
interface CustomController {
nsp: any;
}
interface EggSocketNameSpace {
emit: any
}
}
Copy the code
socket.io-client
window.onload = function () {
// init
const socket = io('http://127.0.0.1:7001', {
// In practice, you can pass arguments here
query: {
room: 'nsp'.userId: `client_The ${Math.random()}`,},transports: ['websocket']}); socket.on('connect'.() = > {
const id = socket.id;
log('#connect,', id, socket);
// Listen to your own ID for p2p communication
socket.on(id, (msg: any) = > {
log('#receive,', msg);
});
});
// Receive online user information
socket.on('online'.(msg: any) = > {
log('#online,', msg);
});
// System events
socket.on('disconnect'.(msg: any) = > {
log('#disconnect', msg);
});
socket.on('disconnecting'.() = > {
log('#disconnecting');
});
socket.on('error'.() = > {
log('#error');
});
window.socket = socket;
};
Copy the code
The client uses socket. IO -client to connect to websocket. The above is the basic link part, the specific implementation should be developed according to the business requirements.
Customer side implementation
In order to ensure the speed of project development, the client chooses ANT DESIGN PRO. Please refer to the tutorial for specific installation steps. Here we show part of the business side code.
JWT front-end use
/** * exception handler */
const errorHandler = (error: { response: Response }): Response= > {
const { response } = error;
if (response && response.status) {
const errorText = codeMessage[response.status] || response.statusText;
const { status, url } = response;
if (response.status === 401) {
window.location.href = '/user/login';
}
notification.error({
message: 'Request error${status}: ${url}`.description: errorText,
});
} else if(! response) { notification.error({description: 'Your network is abnormal and you cannot connect to the server'.message: 'Network exception'}); }return response;
};
/** * Configures the default parameter */ for the request
const request = extend({
prefix: '/api',
errorHandler, // Default error handling
credentials: 'include'.// Whether cookies are included in the request by default
headers: {
authorization: localStorage.getItem('authorization'), // Read the locally saved authorization token}});export default request;
Copy the code
Modify the Request module
import request from '@/utils/request';
export interface LoginParamsType {
username: string;
password: string;
mobile: string;
captcha: string;
}
export async function fakeAccountLogin(params: LoginParamsType) {
return request('/user/getUserToken', {
getResponse: true.// Enable the return header parameter to save the corresponding authorization token for local use
method: 'POST'.data: { params },
});
}
Copy the code
As shown above, if you get the token in the Response header, you can request the interface normally.
The end of the
This project is from zero development, the subsequent series of blog will be launched according to the actual development progress (really f * * king tired), after the completion of the project, will open part of the source code for your reference.
If you have any questions or opinions about the content of the article, please add the wechat Cookieboty communication.
Also follow the public account Cookieboty1024, welcome to join the front end soldier growth camp