700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【笔记-node】《Egg.js框架入门与实战》 《用 React+React Hook+Egg 造轮子 全栈

【笔记-node】《Egg.js框架入门与实战》 《用 React+React Hook+Egg 造轮子 全栈

时间:2019-09-06 01:24:05

相关推荐

【笔记-node】《Egg.js框架入门与实战》 《用 React+React Hook+Egg 造轮子 全栈

课程地址:/learn/1185

第一章 课程导学

01-01 课程介绍

一、Egg.js框架介绍

1、Egg.js是基于Node.js和Koa的一个企业级应用开发框架,可以帮助团队降低开发成本和维护成本。

二、express,koa.js

上手比较简单,但是没有严格的开发规范

三、Egg.js特性

1、提供基于Egg的定制上层框架的能力

2、高度可扩展的插件机制

3、内置多进程管理

4、基于Koa开发性能优异

5、框架稳定,测试覆盖率高

6、渐进式开发

四、涉及技术点

vant ui框架

vue-cli3

moment.js

Egg.js基础

mysql基础

前后端联调

第02章 基础功能讲解

02-01 搭建Egg.js的开发环境

一、官网

1、/zh-cn/intro/quickstart.html

二、建议使用node的LTS版本

LTS:长期稳定版本

current:含目前nodejs最新的特性,相对而言没那么稳定

三、

1、脚手架生成项目

mkdir egg-demo && cd egg-demonpm init egg --type=simple

2、安装相关依赖包

npm install

3、命令启动

npm run dev:开发中npm run start:实际生产项目中使用

四、目录

1、app:项目核心目录。业务逻辑、数据库方面的操作

2、config:针对egg.js的插件进行配置

(1)config.default.js:

(2)plugin.js:

3、test:单元测试的时候使用的

4、autod.conf.js:autod的配置文件

5、.eslintrc、.eslintrc:eslint配置文件

02-02 初识Egg.js的路由

一、Router主要用来描述请求URL和具体承担执行动作的Controller的对应关系,框架约定了app/router.js文件用于同一所有路由规则。

二、通过同一的配置,我们可以避免路由规则逻辑散落在多个地方,从而出现未知的冲突,集中在一起我们可以更方便的来查看全局的路由规则。

三、const { ctx } = this

每次用户请求的时候,框架就会实例化一个context上下文

context主要用来存放用户请求的一些信息

四、Controller:负责解析用户的输入,处理后返回相应的结果

02-03 GET方式请求中的两种传参方式

一、两种传参方式

1、键值对的模式:?id=123&acb=456

路由:http://127.0.0.1:7000/product/detail?id=123

const { ctx } = thisconsole.log(ctx.query)ctx.body = 'id == ctx.query.id'

2、基于/:/123/456

路由:http://127.0.0.1:7000/product/detail2/100

ctx.params.id获取到的id,也就是这个100,是字符串类型。

const { ctx } = thisconsole.log(ctx.params)ctx.body = `id == ctx.params.id`

02-04 POST等其他方式请求方法

一、请求方法

router.head - HEAD

router.options - OPTIONS

router.get - GET

router.put - PUT

router.post - POST

router.patch - PATCH

router.delete - DELETE

router.del - delete是保留字,所以提供了一个delete方法的别名

router.redirect - 可以对URL进行重定向处理

二、POST

const { ctx } = thisconsole.log(ctx.request.body)ctx.body = {id: 123}

这时无法在浏览器请求了,这时候用一个工具:postman

1、postman发送请求,报错。终端提示了报错信息

2、解决方案

config/config.default.js中关闭csrf防御方案。

config.security = {csrf: {enable: false,}}

三、常见的安全漏洞

1、XSS攻击:对Web页面注入脚本,使用JavaScript窃取用户信息,诱导用户操作。

2、CSRF攻击:伪造用户请求向网站发起恶意请求。

3、钓鱼攻击:利用网站的跳转链接或者图片制造钓鱼陷阱。

4、HTTP参数污染:利用对参数格式验证的不完善,对服务器进行参数注入攻击。

5、远程代码执行:用户通过浏览器提交执行命令,由于服务器端没有针对执行函数做过滤,导致在没有指定绝对路径的情况下就执行命令。

四、egg框架针对web常见的安全风险内置了丰富的解决方案

1、利用extend机制扩展了Helper API,提供了各种模板过滤函数,防止钓鱼或XSS攻击。

2、常见的Web安全头的支持。

3、CSRF的防御方案。

4、灵活的安全配置,可以匹配不同的请求url

5、可定制的白名单,用于安全跳转和url过滤。

6、各种模板相关的工作函数做预处理。

在框架中内置了安全差价egg-security提供了默认的安全实践。

五、PUT,更新数据

路由:http://127.0.0.1:7000/product/update/100

const { ctx } = thisconsole.log(ctx.params)ctx.body = `id == ctx.params.id`

六、DELETE

路由:http://127.0.0.1:7000/product/delete/100

const { ctx } = thisconsole.log(ctx.params)ctx.body = `id == ctx.params.id`

02-04 Egg.js中的Service服务

一、服务(Service)

简单来说,Service就是在复杂业务场景下用于做业务逻辑封装的一个抽象层,提供这个抽象有以下几个好处:

1、保持Controller中的逻辑更加简洁

2、保持业务逻辑的独立性,抽irc象出来的Service可以被多个Controller重复调用。

3、将逻辑和展现分离,更容易编写测试用例。

二、使用场景

1、复杂数据的处理,比如要展现的信息需要从数据库获取,还要经过一定的规则计算,才能返回一用户显示。或者计算完成后,更新到数据库。

2、第三方服务的调用,比如GitHub信息获取等。

三、Service服务一般放在app/service文件夹下

02-05 Egg.js中模板引擎的使用

一、View模板渲染

绝大多数情况,我们都需要读取数据后渲染模板,然后呈现给用户。故我们需要引入对应的模板引擎。

框架内置egg-view-ejs作为模板解决方案,并支持多模板渲染,每个模板引擎都以插件的方式引入,但保持渲染的API一致。

二、默认情况下,模板引擎文件会放在app/view文件夹下

三、plugin.js

exports.ejs = {enable: true,package: 'egg-view-ejs',}

.config.default.js

const path = require('path'); // Nodejs内置模块,可解析文件路径config.view = {mapping: {'.html': 'ejs'},root: path.join(appInfo.baseDir, 'app/html'); // 修改index.html等html文件存放的文件夹目录,这是存放在app/html文件夹下root: [ // 多目录配置path.join(appInfo.baseDir, 'app/view'),path.join(appInfo.baseDir, 'app/html')]}config.ejs = {delimiter: "$", // 全局修改分隔符, index.html中用<$= id $>代替<%= id %>}

四、

1、刷新页面,会报错404 not found

因为egg.js中每个方法几乎都是使用同步模式,返回的是promise,所以需要使用await

const { ctx } = this;ctx.render('index.html')

修改成:

const { ctx } = this;await ctx.render('index.html')

五、

controller/home.js

await ctx.render('index.html', {res,lists: ['a', 'b', 'c']}, {delimiter: '$', // 支持对单个文件进行分隔符修改})

view/index.html

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="/public/css/main.css"></head><body><div>这是测试</div><img src="/public/img/img.jpg"><h1>测试样式</h1><p><%=res.id%></p><%# 这是注释 %><ul><%for(var i=0; i<lists.length; i++){%><li><%=lists[i]%></li><%}%></ul></body></html>

六、为什么要学后端的模板引擎

1、后端渲染由来以及,渲染性能得到业界认可

2、利于SEO优化,对纯展示类网站体验较好(如公司官网、某些运营页面)

3、对前后端分离开发模式的补充(单点登录的登录页面)

七、Ejs模板引擎中静态资源的使用和配置

view/user.html

<% include user-header.html %>

八、egg项目中,静态资源默认是放在public的

九、egg项目会默认引入egg-static,egg-static是引用了koajs的static-cache这个插件,然后进行二次封装。

config.default.js

config.static = {perfix: "/assets/", // 将静态资源存放在assets目录下,默认是public文件夹dir: path.join(appInfo.baseDir, "app/assets"),}

index.html

<link rel="stylesheet" type="text/css" href="assets/css/user.css">

<script src="assets/js/user.js"></script>

02-07 Egg.js中静态资源的使用

一、默认情况下,静态资源会放在app/public文件夹下

1、public/img,存放图片资源

2、public/css,存放css资源

3、public/css,存放css资源

第03章 项目实战-前端开发

03-01 搭建前端系统,引入vant组件库

一、vue-cli

npm install -g @vue/clivue --versionvue --helpvue create clientmkdir client & cd clientnpm run serve

二、h5移动端组件库vant

1、vant:轻量、可靠的移动端Vue组件库

npm i --save vant

2、引入组件的方式

自动按需引入组件(推荐):用到babel-plugin-import这个babel插件

手动按需引入组件

导入所有组件

通过CDN方式

三、.babelrc中

{"plugins": [["import", {"libraryName": "vant","libraryDirectory": "es","style": true}]]}

引入vue-router

一、npm i vue-router

二、App.vue

<div id="app"><router-view></router-view></div>

1、src/router/index.js,引入vue-router,配置routes

Vue.use(VueRouter)const router = new VueRouter({mode: 'hash',routes: []})

2、main.js

import router from './router'new Vue({router,render: h => h(App)}).$mount('#app')

03-05 开发文章详情页面

一、this.$router.push()进行路由的跳转

第04章 项目实战-后端开发

04-01 创建mysql表结构

一、数据库

终端操作

mysql -uroot -p;

show databases;

create database egg_article;

use egg_article;create table article(id int(10) not null auto_increment,img text default null comment '缩略图',title varchar(80) default null comment '文章标题',summary varchar(300) default null comment '文章简介',content text default null comment '文章内容',createTime timestamp default null comment '发布时间',primary key(id))engine=InnoDB AUTO_INCREMENT=1 comment '文章表';insert into article(img, title, summary, content, createTime) values('编程必备', '/szimg/5d1032ab08719e0906000338.jpg', '介绍编程必备基础知识', '快速、系统补足您所需要的知识内容', '-08-10 10:20:20');

use egg_article;

show tables

desc article;

select * from article;

04-02 egg.js连接mysql数据库

一、egg-mysql

框架提供了egg-mysql插件来访问MySQL数据库。这个插件既可以访问普通的MySQL数据库,也可以访问基于MySQL协议的在线数据库服务。

二、

npm i egg-mysql

04-04 引入moment.js处理时间问题

一、

npm i moment

04-05 egg.js开发文章首页和详情页接口

一、插入数据

const result = await app.mysql.insert('article', params);

二、查询文章列表

const result = await app.mysql.select('article');

三、查询文章详情

1、查询单个表,使用get方法

const result = await app.mysql.get('article', { id })

04-06 前后端接口联调

一、proxy的changeOrigin:开启虚拟服务器,让虚拟服务器去请求代理服务器,这样就相当于是两台服务器之间进行数据的交互,就不用担心跨域的问题。

课程地址:/class/452.html

(aSuncat-0707: 前后端涉及的内容比较多,可以多听几遍)

第01章 关于这门课,你需要知道的

01-01 课前须知,这里有你需要了解的一切

一、课程涉及框架

1、react

umiJS:react工具集锦,路由管理、数据mock,其他相关插件

egg.js:是nodejs的一个框架,有比较严格的项目管理规范,支持路由配置,controller配置器,service服务,模板渲染,默认支持很多实用的插件

2、

自定义hook:提高研发效率

数据流工具think-react-store: react数据流解决方案

Project-libs:常用函数集锦

IntersectionObserver:滚动加载,图片懒加载

二、后端核心技术

egg.js:主框架

jwt:用户验证

Mysql:数据存储

Sequelize:ORM框架,操作mysql

扩展egg框架:提交研发效率

自定义中间件和插件:拦截请求等处理

三、技术架构图

四、前端干货

1、自定义hook

useTitleHook:动态修改浏览器title

useHttpHook: 发送http请求,对某些状态值进行监听

useObserverHook: 监听dom元素是否进入展示区域

useImgHook: 实现图片懒加载

2、自定义组件

createPortal:createPortal在根节点之外创建新的节点

Modal:

ErrorBoundary:捕获错误,展示友好信息

MenuBar:底部Menu

LazyLoad: 懒加载

ShowLoading:底部加载

五、后端干货(手把手开发)

1、中间件

httpLog: 日志中间件

userExist:判断用户是否存在

2、插件

egg-auth:验证用户

egg-info:获取系统信息

3、框架扩展

application:egg.js的应用实例

helper:帮助函数,将要使用的函数全都挂载到egg.js中,这样使用时无需引入,直接用helper即可

requst:对请求来进行扩展

context:对上下文扩展

response: 对response扩展

六、课程安排

react基础进阶 -> 开发组件 -> 开发自定义hook -> egg.js基础 -> egg.js高级 -> 前端界面开发 -> 后端接口开发 -> 系统安全处理 -> 项目发布

七、学习基础

熟悉react.js基础语法

了解node.js基础语法

对全栈开发感兴趣

第02章 React核心内容梳理及自定义组件开发

02-01 本章概览

一、组件经历的不同阶段

二、组件之间的通信

1、父子组件通信

2、兄弟组件通信

3、组件跨页面通信

三、Lazy和Suspence实现懒加载

三、组件报错了怎么办:ErrorBoundary

可将错误信息上传,便于错误的排查

四、CreatePortal创建自定义弹窗

五、章节介绍

UmiJs入门介绍

React组件生命周期

React组件通信方式

Dva数据处理和mock

Context实现数据流管理

组件懒加载

ErrorBoundary错误边界

createPortal自定义弹窗

Ref api操作dom和组件

02-02 前端开发环境搭建

一、vscode设置

command + shift + p:选择将”code“命令添加到PATH

这样就在终端输入code . 就可以在终端打开vscode编辑器了。

二、依赖包管理工具:npm、yarn

02-03 (章节缺失)

02-08 React组件通信

一、父组件向子组件传值

二、子组件向父组件传值

三、兄弟组件之间的传值

1、父组件作为中间层

2、如果嵌组件套得非常多,【父组件作为中间层】的方式就不可行了。

(1)dva

(2)context api

02-09 Dva数据处理及数据mock

一、models下的namespace是可选的,如果有,就取namespce,否则取文件名。

二、reducers:同步的方法

effects:异步的方法

call:调用异步函数

put: 事件派发

// 同步reducers: {getLists(state, action) {return {...state,lists: Array(10).fill(action.payload)}},},// 异步effects: {*getListsAsync({ payload }, { call, put }) {yield put({type: 'getLists',payload,})}}

三、umi的mock功能是对express的封装。

02-10 基于react context api实现数据流管理

一、子组件(消费者组件),订阅Provider的属性,Provider组件值改变,消费者组件会被重新渲染。

1、contextType

2、consumer

02-11 LazyLoad组件开发【基于lazy与suspense实现的懒加载组件】

一、.umirc.js 中dynamicImport: true, // 按需加载

1、页面级别:每个页面内所有组件打包成1个js

二、希望对每个页面的每个组件实现按需加载。

const Demo = lazy(() => import('./demo'))<Suspense fallback=(<div>loading...</div>)<Demo /></Suspense>

三、components/LazyLoad/index.js

_renderLay = () => {let lazy;const { component, delay, ...other } = this.props;if (!component || component.constructor.name != 'Promise') {Lazy = import('./error')}Lazy = lazy(() => {return new Promise(resolve) => {setTimeout(() => {resolve(component)}, delay || 300)}})return <Lazy {...other} />}

02-12 ErrorBoundary组件开发[基于React错误边界技术实现的组件]

一、错误处理:react提供的2个构造函数

getDerivedStateFromError()

componentDidCatch()

二、src/components/ErrorBoundary/index.js

import React, { Component } from 'react';export default class ErrorBoundary extends Component {constructor(props) {super(props);this.state = {flag: false,}}static getDerivedStateFromError(error) {return {flag: true,}}/* error: 抛出的错误* info: 带有componentStack key的对象,其中包含有关组件引发错误的栈信息*/copmponentDidCatch(error, info) {}render() {return (<div>{this.state.flag ? <h1>发生错误,请稍后再试!</h1> : this.props.children}</div>)}}

1、layouts/index.js中引入ErrorBoundary组件

错误边界是在父组件监测子组件的错误,并不能监测本身发生的错误。

三、可选技术

house?.info?.activity

02-13 Modal组件开发【基于createPortal创建自定义弹窗组件】

一、ErrorBoundary,无法处理组件点击事件内部的错误,setTimeout内部的错误。

二、src/CreatePortal/index.js

import React, { Component } from 'react';import ReactDOM from 'react-dom';export default class CreatePortal extends Component {constructor(props) {super(props);this.body = document.querySelector('body');this.el = document.createElement('div');}componentDidMount() {this.el.setAttribute('id', 'protal-root');this.body.appendChild(this.el);}componentWullUnmount() {this.body.removeChild(this.el);}render() {return ReactDOM.createPortal(this.props.children, this.el)}}

createPortal(react node节点,希望插入的dom节点)

02-14 使用ref api来操作dom和组件

一、数据流之外,父组件操作子组件,或操作内部组件dom元素,则可以用ref

第03章 React Hooks开发模式详解及自定义hook开发

03-01 react hook api - 新的组件开发模式

一、hook api主要用于function 类型的组件

二、useEffect方法虽然可以执行异步函数,但是不支持async, await

// 错误写法useEffect(async() => {})

1、async方法写在useEffect方法里面

useEffect(() => {async function demo() {console.log('use')}demo}, [count])

2、async写在useEffect外面

async function demo() {console.log('demo')}useEffect(() => {console.log('use')demo()}, [count])

三、useLayoutEffect是在所有dom渲染完后,才同步执行useLayoutEffect。

一般在这个方法内做dom操作。

03-03 useTitleHook【根据url修改页面title的自定义hook】

一、useTitleHook.js

import { useLayoutHook, useState } from 'react';export default function useTitleHook(title) {const [state, setState] = useState();useLayoutEffect(() => {document.title = title;setState(title)}, [title])return state;}

二、jsconfig.json

1、配置vscode相关的配置

{"compilerOptions": {"baseUrl": "src","paths": {"@/hooks": ["hooks/index"]}}}

2、这样import { useTitleHook } from ‘@/hooks’;,鼠标放到@/hooks上,就能看到是从哪里引入的

03-05 使用think-react-store实现数据处理(基于react hooks和context实现的数据流工具)

一、think-react-store:基于react hooks和context实现的数据流工具

二、

store/stores/user.js

export default {state: {id: undefined,username: undefined,}reducers: {getUser(state, payload) {return {...state,...payload,}}},effects: {async getUserAsync(dispatch, rootState, payload) {await new Promise(resolve => {setTimeout(() => {resolve();}, 1000)})dispatch({type: 'getUser',payload,})}}}

store/stores/index.js

import { default as User } from './user';

store/index.js

import React, { useState, useEffect } from 'react';import { StoreProvider } from 'think-react-store';import * as store from './stores';import log from 'think-react-store/middleware/log';import User from './user';export default function(props) {const [state, setState] = useState();useEffect(() => {}, [])return (<StoreProvider store={store} middleware={[log]}><User /></StoreProvider>)}

store/user.js

import React, { useState, useEffect } from 'react';import { useStoreHook, useStateHook, useDispatchHook } from 'think-react-store';export default function(props) {const [state, setState] = useState();const { user: { id, usename, getUserAsync } } = useStoreHook();const states = useStateHook(); // const states = useStateHook('user'); // 仅返回用户相关的全局stateconsole.log(states);const dispatch = useDispatchHook(); //const dispatch = useDispatchHook('user'); // 这样dispatch()里就不用写keyconst handleClick = () => {getUserAsync({id: 20,usename: 'admin2',})}const handleClick2 = () => {dispatch({key: 'user',type: 'getUserAsync',payload: {id: 20,username: 'admin2'}})}useEffect(() => {getUserAsync({id: 10,usename: 'admin',})})return (<div>user-id: {id}<br/>username: {username}<br/><button onClick={handleClick}>修改</button></div>)}

03-05 Fiber架构解析

一、为什么需要Fiber架构

react16之前的渲染流程

Fiber架构:渲染阶段分成调度阶段、提交阶段

二、Fiber的执行流程

Fiber是一个js对象数据结构。

三、Fiber对React生命周期API的影响

调度阶段是可以执行多次的。所以比如发送请求等不适合放在调度阶段。

第04章 为什么应用Egg.js

04-01 Egg.js企业及开发的利器概述

一、企业级应用的特点

功能完善

规范性高

便于扩展(插件方面的扩展,帮助函数方面的扩展)、升级

二、Egg.js的特点

提供基于Egg定制上层框架的能力

高度可扩展的插件机制(有别于中间件模式)

内置多进程管理

基于koa开发,性能优异

框架稳定,测试覆盖率高

渐进式开发

三、egg.js与koa/express对比

04-02 Egg.js初体验

app是Egg的一个实例

04-03 Node.js中近程

一、nodejs单线程,单进程

二、有时需要子进程中执行某些shell命令

三、进程

1、child_process模块

2、cluster模块

nodejs只能用cpu中的某一个内核,这样会造成极大的浪费

3、master进程与cluster进程的通信

四、const { exec, spawn } = require('child_process');

exec、spawn都是用来创建子进程的。

exec:创建子进程,并且将进程执行的结果缓存起来,之后将缓存的结果返回给回调函数。

spawn:返回的是一个stream流

五、child_process.js

const { exec, spawn } = require('child_process');exec('cat a.js', (error, stdout, stderr) => {});const ls = spawn('ls', ['-a'], { encoding: 'utf8' });ls.stdout.on('data', (data) => {});ls.stderr.on('data', (data) => {});ls.on('close', (code) => {})

六、cluster.js

const cluster = require('cluster');const http = require('http');const os = require('os');const cpus = os.cpus().length;console.log(cpus)if (cluster.isMaster) {console.log('主进程 ${process.pid} 正在运行');// 衍生工作进程for (let index = 0; index < cpus; index++) {cluster.fork();}} else {// 工作进程可以共享任何tcp连接// 这里我们共享的是一个http服务器http.createServer((req, res) => {res.writeHead(200, {'Content-type': 'text/html; charset=utf-8'});res.write('你好');res.end()}).listen(8000)console.log(`工作进程 ${process.id} 已经启动`)}

第05章 Egg.js基础-路由/控制器/服务/模板引擎等

05-01 Egg.js中Controller的使用和单元测试

一、Controller

Controller中的方法可以是同步的,也可以是异步的。但是egg.js规定Controller里的方法是异步的。

二、测试文件是以.test.js为后缀的。

三、user.test.js

'use strict';const { app } = require('egg-mock/bootstrap');describe('user test', () => { // arguments:测试用例的名称,回调函数it('user index', () => {return app.httpRequest().get('/user').expect(200).expect('user index')});it('user lists', async () => {await app.httpRequest().get('/user/lists').expect(200).expect('[{"id":123}]')})});

终端执行yarn test

05-03 Egg.js路由中post, put, delete等请求的处理及参数校验

一、参数校验:egg-validator

plugin.js

exports.validate = {enable: true,package: 'egg-validate'}

app/user.js

const rule = {name: { type: 'string' },age: { type: 'number' }}ctx.validate(rule)

05-04 Egg.js中的Service服务和单元测试

test/app/service/user.test.js

'use strict';const { app, assert } = require(''egg-mock/bootstrap');deacribe('service user test', () => {it.only('test detail', async () => {const ctx = app.mockContext();const user = await ctx.service.user.detail(10);assert(user);assert(user.id === 10);})})

05-07 Egg.js中的cookie设置和使用以及如何设置中文cookie

一、Cookie

HTTP请求都是无状态的,但是我们的Web应用通常需要知道发起请求的人是谁。为了解决这个问题,HTTP协议涉及了一个特殊的请求头:Cookie。服务端可以通过响应头(set-cookie)将少量数据响应给客户端,浏览器会遵循协议将数据保存,并在下次请求同一个服务的时候带上(浏览器也会遵循协议,只在访问符合Cookie指定规则的网站时带上对应的Cookie来保证安全性)

1、Cookie是运行在浏览器上的

二、通过ctx.cookies,可以在controller中便捷、安全地设置和读取Cookie

三、egg.js中默认对Cookie进行了集成,封装在ctx上下文。

ctx.cookies

const cookies = ctx.cookies.get('user');ctx.cookies.set('user', JSON.stringify(body));ctx.cookies.set('user', JSON.stringify(body), {maxAge: 1000 * 60 * 10, // 过期时间httpOnly: true, // 只允许服务端操作cookie, document.cookie获取不到cookie的值})

四、egg.js无法直接设置中文cookie。解决方法

1、加密

ctx.cookie.set('zh', '测试', {encrypt: true,});const zh = ctx.cookies.get('zh', {encrypt: true,});

2、base64

app/controller/user.js

encode(str = '') {return new Buffer(str).toString('base64');}decode(str = '') {return new Buffer(str, 'base64').toString();}ctx.cookies.set('base64', this.encode('中文base64'));const base64 = this.decode(ctx.cookies.get('base64'));

05-08 Egg.js中session的配置和使用

一、session

Session的实现是基于Cookie的,默认配置下,用户Session的内容加密后直接存储在Cookie中的一个字段中,用户每次请求我们网站的时候都会带上这个Cookie,我们在服务端解密后使用。

二、Session、Cookie的区别

四、async index() {const session = ctx.session.user;console.log(session);}// 保存sessionctx.session.user = body;

五、session是可以直接支持中文的

六、config.default.js

config.session = {key: 'IMOOC',httpOnly: true, // 实际项目中都是用true,来提高安全性maxAge: 1000 * 5,renew: true,}

2、对session进行扩展

app.js

module.exports = app => {const store = {}app.sessionStore = {async get(key) {console.log('--store--', store);return store[key]}async set(key, value, maxAge) {store[key] = value}async destroy(key) {store[key] = null;}}}

05-09 Egg.js中使用HttpClient请求其他接口

一、User server, Article server, Order server, Other server

二、

contoller/home.js

class HomeController extends Controller {async index() {const { ctx } = this;const res = await ctx.service.user.detail(20);console.log(res);ctx.body = 'hi, egg';}}

contoller/curl.js

class CurlController extends Controller {async curlGet() {const { ctx, app } = thisconst res = await ctx.curl('http://localhost:7001/', {dataType: 'json',})console.log(res);ctx.body = {status: 200,data: res.data,}}}

第06章 Egg.js高阶-插件中间件扩展等

06-01 中间件

一、中间件是按照顺序,由外而内,一层层地执行,并且每个中间件都会执行2次。

实际项目中,我们一般使用中间件对请求进行拦截。

二、app/middleware

m1.js

module.exports = options => {return async(ctx, next) => {console.log('m1 start');await next();console.log('m1 end');}}

m2.js

module.exports = options => {return async(ctx, next) => {console.log('m2 start');await next();console.log('m2 end');}}

httpLog.js

const dayjs = require('dayjs');const fs = require('fs'); // 引入文件处理模块module.exports = options => {console.log(options) // config.default.js中的 config.httpLog对象就是它的参数return async (ctx, next) {const sTime = Date.now();const startTime = dayjs( Date.now()).format('YYYY-MM-DD HH:mm:ss');await next(); // 如果没有这行,浏览器会报错:404 not foundconst log = {method: req.method,url: req.url,data: req.body,startTime,endTime: dayjs( Date.now()).format('YYYY-MM-DD HH:mm:ss'),timeLength: Date.now() - sTime}// console.log(log)const data = dayjs( Date.now()).format('YYYY-MM-DD HH:mm:ss') + ' [httpLog] ' + JSON.stringify(log) + '\r\n';fs.appendFileSync(ctx.app.baseDir + 'httpLog.log', data)}}

三、config.default.js

// config.middleware = ['m1', 'm2'];config.middleware = ['httpLog'];config.httpLog = { // 中间件的参数type: 'all',}

06-02 丰富的扩展方式

一、扩展方式

二、扩展一般放在app/extend文件夹下

三、对application的扩展有2个,1是方法层面的扩展,2是属性的扩展

四、app/extend/application.js

const path = require('path');module.exports = {// 方法扩展package(key) {const pack = getPack();return key ? pack[key] : pack;}// 属性扩展get allPackage() {return getPack();}}function getPack() {const filePath = path.join(process.cwd(), 'package.json');const pack = require(filePath);return pack;}

app/controller/home.js

class HomeController extends Controller {async newApplication() {const { ctx, app } = this;const packageInfo = app.package('scripts');const allPack = app.allPackage;ctx.body = 'newApplication';}// 对context上下文进行扩展async newContext() {const { ctx } = this;const params = ctx.params();ctx.body = 'newContext';}async newRequest() {const { ctx } = this;const token = ctx.request.tokenctx.body = token;}async newResponse() {const { ctx } = this;ctx.response.token = 'abc123';const base64Parse = ctx.helper.base64Encode('newResponse');ctx.body = base64Parse;}}

app/extend/context.js

获取get/post的参数是使用不同的方式,现在我们希望用的是同一种方式

context.js

module.exports = {params(key) {const method = this.request.method;if (method === 'GET') {return key ? this.query[key] : this.query;} else {return key ? this.request.body[key] : this.request.body;}}}

app/extend/request.js

一般情况下,对request, response的扩展一般都是对属性的扩展

module.exports = {// 获取相关的tokenget token() {console.log('header', this.header);return this.get('token');}}

app/extend/response.js

module.exports = {// 希望能设置相关的tokenset token(token) {this.set('token', token);}}

app/extend/helper.js

module.exports = {base64Encode(str = '') {return new Buffer(str).toString('base64');}}

06-04 插件机制

一、插件

1、中间件更适合处理请求,插件不仅可以包含中间件所有功能,还可以处理业务逻辑。

2、Egg.js中的插件相当于一个微型应用。

3、插件不包括router.js和controller控制器(可能会与主项目中的路由产生冲突)

二、项目目录下新建lib文件夹,插件都会放在lib文件夹下的plugin文件夹下,plugin里的文件一般以egg-开头

lib/plugin/egg-auth/app/package.json

{"name": "egg-auth","eggPlugin": {"name": "auth"}}

lib/plugin/egg-auth/app/middleware/auth.js

module.exports = options => {return async (ctx, next) => {const url = ctx.request.url;const user = ctx.session.user;if (!user && !options.exclude.includes(ctx.request.url.split('?')[0])) {ctx.body = {status: 1001,errMsg: '用户未登录',}} else {await next();}}}

config/plugin.js

这里用的是本地的插件,不能用pacakge属性,package属性一般是指线上安装的依赖包

path与package属性是互斥的。

exports.auth = {enable: true,path: path.join(__dirname, '../lib/plugin/egg-auth')}

app.js

module.exports = app => {app.config.corMiddleware.push('auth');}

config/config.default.js

config.auth = {exclude: ['/home', '/user', '/login', '/logout']}

06-05 Egg.js定时任务

一、定时任务

1、定时上报应用状态,便于系统监控

2、定时从远程接口更新数据

3、定时处理文件(清除过期日志文件)

二、

lib/plugin/egg-info/app/extend

三、app/schedule文件夹下存放的都是定时任务

app/schedule/get_info.js

require('egg').Subscription;class getInfo extends Subscription {static get schedule() {return {interval: 3000,cron: '*/3 * * * *', // 每隔3秒钟type: 'worker' // 类型:'all' 、 ’worker‘, all:每个worker进程都会执行这个定时任务, worker:master进程会指定一个进程,来单独执行这个任务}}async subscribe() {const info = this.ctx.info;console.log(Date.now(), info)}}module.exports = getInfo;

第07章 Egg.js操作Mysql数据库

07-01 安装Mysql数据库

一、

show database;

create database egg;

二、可视化数据图工具

mysql workbench

07-02 mysql入门,基础增删改查操作

一、show databases;

二、demo.sql

-- 删除数据库drop database egg;-- 创建数据库create database egg;-- 创建表use egg;create table user(id int(10) not null auto_increment,name varchar(20) not null default 'admin' comment '用户名',pwd varchar(50) not null comment '密码',primary key(id))engine=InnoDB charset=utf8;-- 查看表show tables;-- 查看表结构desc user;-- 删除表drop table user;-- 插入表数据insert into user values(1, 'user1', '123');insert into user(name, pwd) values('user2', '123');-- 查询表数据select * from user;select id, name from user;select id, name from user where id = 1;-- 修改表数据update user set pwd = '123456' where id = 1;-- 删除表数据delete from user where id = 2;

07-03 使用egg-mysql操作数据库

一、

yarn add egg-mysqlyarn dev

config/plugin.js

exports.mysql = {enable: true,package: 'egg-mysql'}

config/config.default.js

config.mysql = {app: true, // 是否将mysql挂载到app下agent: false,client: {host: '127.0.0.1',port: '3306',user: 'root',password: 'abc123456',database: 'egg',}}

二、egg-mysql的使用方式比较简单,比较适合中小型项目

07-04 Egg.js中使用Sequelize操作mysql

一、sequelize是一个crm框架

二、

yarn add egg-sequelize mysql2yarn dev

exports.sequelize = {enable: true,package: 'egg-sequelize'}

config.sequelize = {dialect: 'mysql', // 数据源host: '127.0.0.1',port: '3306',user: 'root',password: 'abc123456',database: 'egg',define: {timestamps: false, // 在使用sequelize时,不需要sequelize这个框架为我们自动添加时间相关的字段freezeTabelName: true, // 冻结表名称,使用sequelize的时候,使用原始的表名称,而不需要sequelize框架额外地处理表名称}}

三、app/model,里面是我们的模型文件

app/model/user.js

module.exports = app => {const { STRING, INTEGER } = app.Sequelize;const User = app.model.define('user', { // 模型名称,一般是表名称, 'user'id: { type: INTEGER, primaryKey: true, autoIncrement: true },name: STRING(20),pwd: STRING(50)}); }

app/controller/user.js

const res = await ctx.model.User.findAll({// where: {// id: 2,// }limit: 1,offset: 1})

const res = await ctx.model.User.findByPk(ctx.query.id);

// 更新之前判断数据是否存在const user = await ctx.model.User.findByPk(ctx.request.body.id);if (!user) {ctx.body = {status: 404,errMsg: 'id不存在',}return;}const res = user.update(ctx.request.body);ctx.body = {status: 200,data: res,}

第08章 前端界面开发及功能优化

08-01 本章概览

一、章节目标

1、完成前端界面开发

2、实现列表滚动加载、图片懒加载效果

3、使用mock数据模拟接口(umijs)

二、系统模块

三、技术要点

1、IntersectionObserver,元素是否进入到可视区域

四、学习收获

1、可以学习到前端系统的开发流程

2、了解并实现滚动加载和图片懒加载的思路

3、前端项目的优化思路(公共组件、缓存、骨架屏)

08-02 实现网站的底部导航功能

一、vscode用func命令生成新的组件

二、react-icons,是针对react项目封装的icon

yarn add react-icons

// bootstrap的iconsimport { BsHouseDoorFill, BsHouseDoor} from 'react-icons/bs'

08-04 为首页添加数据

一、如果父组件内的子组件没有数据交互,数据请求就放在父组件中

08-06 初识IntersectionObserver,实现UseObserverHook

一、IntersectionObserver提供了一种异步观察目标元素与其祖先元素及顶级文档视窗(viewport)交叉状态的方法。

二、

三、使用这个特性会比较消耗性能,一般我们会在页面初始化的时候观察这个dom节点,离开页面时取消观察

let observer;useEffect(() => {console.log('进入页面');observer = new IntersectionObserver(entries => {console.log(entries); // 重点关注intersectionRadio, isIntersecting属性});observer.observe(document.querySelector('#loading'));return () => {console.log('离开页面')if(observer) {// 解绑元素observer.unobserve(document.querySelector('#loading'));// 停止监听observer.disconnect();}}}, [])

08-07 使用useObserverHook实现滚动加载(上)

一、

/*** 1、监听loading是否展示出来(loading:请求的节点)* 2、修改分页数据* 3、监听分页数据的修改,发送接口,请求下一页的数据* 4、监听loading变化,拼装数据(loading:数据是否变化的状态)*/useObserverHook('#loading'), (entries) => {}, null)

08-08 使用useObserverHook实现滚动加载(下)

一、获取url参数,umi

import { useLocation } from 'umi'const { query } = useLocation()body = {code: query?.code}

08-09 使用useImgHook实现图片懒加载

一、useImageHook.js

/*** 1、监听图片是否进入可视区域* 2、将src属性的值替换为真是的图片地址,data-src* 3、停止监听当前的节点*/const useImgHook(ele, callback, watch = []) => {}

const dataSrc = item.target.getAttribute('data-src');item.target.setAttribute('src', dataSrc);observer.unobserve(item.target);

08-10 优化-提取公共组件,使用枚举,引入project-libs

一、id,loading在search页面是唯一的

二、antd-mobile的日历组件的svg标签中的元素有id是loading,所以search页面的loading这个id得改一下。

三、enums/common.js,可导出一些常量

export const LOADING_ID = 'mk-loading';

enums/index.js

import * as CommonEnum from './common';export {CommonEnum}

使用

import { CommonEnum } from '@/enums'

四、工具函数库

project-libs(文档:https://cpagejs.github.io/project-libs/)

06-11 民宿详情页面开发

一、banner滑动

react-awesome-swiper

06-12 为民宿详情页添加数据流管理(上)

一、不同组件之间的交互,useHttpHook就不适用了。

二、数据流:think-react-store

effects:异步方法,可以在其中发送请求

三、滚动加载

search页面:useHttpHook方式

民宿详情页:数据流方式

/*** 1、监听loading是否展示出来* 2、触发reload, 修改分页* 3、监听reload变化,重新请求接口* 4、拼装数据*/

08-13 为民宿详情页添加数据流管理(下)

一、

import { history } from 'umi';history.push({pathname: '',query: {id: '',}})

import { useLocation } from 'umi';const { query } = useLocation();

08-14 为订单页面添加滚动加载效果(使用onObserverHook,但不监听数据)

一、不用进行数据监听,

/*** 1、页面初始化时候请求接口,useEffect* 2、监听loading组件是否展示出来,useObserverHook* 3、修改page, pageNum+1,再次重新请求接口* 4、拼装数据,然后page*/

08-19 通过umi运行时配置,对页面进行登录验证

一、cookie

1、右上角登录/注册,如果已经登录了,就显示用户名。

2、点击“我的”,如果未登录,则跳转到登录页面

umi运行时配置

src/appp.js:可以修改路由,复写render

import { cookie } from 'project-libs';import { history } from 'umi';// 初始加载,路由切换的时候进行响应的逻辑export function onRouteChange(route) {const nowPath = routes.routes[0].routes.filter(item => item.path === route.location.pathname);const isLogin = cookie.get('user');if(nowPath.length === 1 && nowPath[0].auth && !isLogin) {history.push({pathname: '/login',query: {from: route.location.pathname}})}}

08-20 使用React.memo减少渲染次数

一、

header组件多次渲染,用Memo

import { memo } from 'react';function areEqual(prevProps, nextProps) {if (prevProps.citys === nextProps.citys && prevProps.cityLoading) {return true; // 允许组件重新渲染} else {return false;}}export default memo(Search, areEqual);

08-21 优化-订单页面添加骨架屏

一、思路

1、通过伪元素实现骨架样式

(1)用伪元素是因为骨架屏只展示区块,区块不包含文字、图片

2、制作布局组件,添加骨架样式

3、替换默认Loading效果

二、这章是针对单独的页面写单独的骨架屏的

三、、global.css

.skeletons {position: relative;display: block;overflow: hidden;width: 100%;min-height: 20px;background-color: #ededed;}.skeletons:empty::after {display: block;content: ' ';position: absolute;width: 100%;height: 100%;transform: translateX(-100%);background: linear-gradient(90deg, transparent, rgba(216, 216, 216, 0.6), transparent);animation: loading 1.5s infinite;}@keyframes loading { /* 骨架屏动画*/from {left: -100%;}to {left: 120%;}}

四、src/skeletons

src/skeletons/OrderSkeletons

第09章 服务端用户模块实现及优化

09-01 本章概览

一、后端

二、章节目标

完成用户模块的接口开发

使用JWT技术验证用户:用户信息加密,生成字符串,之后对字符串解密

提取公共逻辑,优化系统

三、技术要点

redis主要保存核心数据

mysql主要保存业务数据

四、学习收获

1、学习如何开发登录、注册接口以及注意事项

2、学习到如何使用JWT技术进行用户验证

3、如何根据项目需求进行优化(框架扩展、中间件、公共类)

09-02 创建用户表,建基于Seuelize编写用户模型

一、创建数据库

app.sql

create database egg_house;use egg_house;-- 用户表create table `user`(`id` int not null auto_increment,`username` varchar(20) default null comment '密码',`createTime` timestamp default null comment '创建时间',primary key(`id`))engine=InnoDB auto_increment=1 default charset=utf8 comment=‘用户表’;

二、

app/model/user.js

module.exports = app => {const { STRING, INTEGER, TEXT, DATE } = app.Sequelize;const User = app.modeldefine('user', {id: { type: INTEGER, primaryKey: true, autoIncrement: true },username; STRING(20),createTime: DATE,});return User;}

09-03 开发用户注册接口

一、配置项

config/config.default.js

const userConfig = {salt: 'muke'}

app/controller/user.js

const { app } = this;const salt = app.config.salt

09-04 扩展Egg.js的帮助函数

一、存在的问题

1、返回给前端的数据,有些是不需要展示的(如密码)

2、dayjs多处使用,推荐将dayjs写成eggjs中的帮助函数

二、app/extend/helper.js

time() {return dayjs().format('YYYY-MM-DD HH:mm:ss')}

ctx.helper.time();

三、返回的数据都有dataValue

ctx.session.userId = user.id;ctx.body = {status: 200,data: {...ctx.helper.unPick(user.dataValues, ['password']),createTime: ctx.helper.timestamp(user.createTime);}}

09-06 什么是JWT技术

一、JWT全称JSON Web Tokens,是一种规范化的token。它里面包含用户信息,具有验证用户身份、方式CSRF攻击等优点。

二、jwt官网:https://jwt.io/introduction

三、JWT结构

四、JWT使用

09-07 使用JWT改造注册和登录接口,并联调登录注册接口

一、

yarn add egg-jwt

cofig/中对插件进行配置

config.jwt = {}

09-09 优化用户登录验证插件

一、lib/plugin/egg-auth/app/middleware/auth.js

实际项目中,一般不会将缓存放在session中,因为如果服务重启,session会丢失,如果有多台服务,会导致session不一致。

09-10 redis的简单使用,将用户基础信息存储在redis中

一、redis可以将缓存与业务解耦

二、Redis是一个基于内存的高性能key-value数据库。具有存储速度快、支持丰富的数据类型、过期后自动删除等特点。被广泛地应用于企业级项目。

二、安装

brew install redis

启动,开机的时候同时进行启动

brew services start redis

进入redis终端

redis-cli

设置值

set id 1

查看

get id

设置过期时间

expire id 3 // id的过期时间为3秒

三、/usr/local/etc里有配置文件redis.conf

搜素requirepass,requirepass可以用来设置redis密码

四、egg.js连接redis

yarn add egg-redis

五、app/controller/user.js

await app.redis.set(username, 1, 'EX', 5);

六、插件、中间件如果想获取app的实例,用ctx.app就可以了

lib/plugin/egg-auth/app/middleware/auth.js

const user = await ctx.app.redis.get(ctx.username);

09-11 将公共逻辑写在BaseController和BaseService里面,并开发新的插件

一、缓存中是否有用户名,而用户名是从前端传过来的token中解析出来的。重新登录,后端会重新生成token,

二、egg.js提供了中间件的多种使用方式

三、app/router.js

const userExist = app.middleware.userExist(); // userExist中间件可以不在config.default.js中配置,即不应用到整个系统中,而是直接应用于某些接口router.post('/api/user/detail', userExist, contoller.user.detail);

四、优化

1、用户注册登录后,将token保存在redis中

2、改造了登录验证插件,之前登录验证是没有对新旧token进行比较的

3、移除密码、时间处理,封装成共用的方法

4、使用了之前公用的方法promise

5、创建了公用的BaseController, BaseService

第10章 服务端民宿&订购模块实现及优化

10-01 创建民宿、评论表以及编写Sequelize模型

一、server/app.sql

-- 民宿表create table `house`(`id` int not null auto_increment,`name` varchar(50) default null comment '房屋名称') engine=InnoDB auto_increment=1 default charset=utf8 comment='房屋表';--图片表create table `imgs`(`id` int not null auto_increment,`url` varchar(500) default null comment '图片地址',`houseId` int not null comment '房屋id',`createTime` timestamp default null comment '创建事件',primary key(`id`)) engine=InnoDB auto_increment=1 default charset=utf8 comment='图片表';

1、通过设置houseId,将民宿表与图片表关联(外链?)

10-02 开发egg-notFound插件,处理接口不存在问题

一、<ErrorBoundary>推荐在需要的页面使用,而不是直接写在layouts/index.js中

二、插件,lib/plugin

1、egg-auth,判断用户是否存在

egg-notFound,判断接口是否存在

2、egg-notFound需要放在egg-auth前面

app.config.coreMiddleware.push('notFound');

10-03 获取城市列表数据,基于Sequelize多表联查编写热门民宿接口

一、城市接口,采用第三方接口

const result = await app.httpClient.request()

二、service/house.js

await ctx.model.House.findAll({limit: 4,order: [ // 排序['showCount', 'DESC'],],attributes: {exclude: ['startTime', 'endTime', 'publishTime'], // 去掉数据库中某些字段,不在接口中返回给前端}})

三、多表关联

新的特性:associate

include属性

10-04 编写搜索民宿,与前端联调

一、

10-05 编写民宿详情接口,与前端联调

一、model中,通过设置get方法修改获取到的值,如转换成时间戳

publishTime: {type: DATE,get() {return new Date(this.getDataValue('publishTime')).getTime()}}

10-06 编写添加评论和评论列表接口,与前端联调

createTime: ctx.helper.time()

10-11

第11章 项目安全

11-01 xss常见攻击方法与解决思路

一、web应用中存在的安全风险

1、篡改网页内容

2、窃取网站内部数据

3、网页中植入恶意代码,使用户利益得到侵害

11-02 CSRF常见攻击方式与解决思路(开发allow-hosts插件)

一、开发新的插件,对所有接口进行拦截

11-03 如何对接口限流,避免无限制请求(开发egg-interfaceLimit插件)

一、思路

/****3秒内最多允许3个接口请求* 1、设置计数器,每次请求加1,保存起始时间* 2、超过3秒,计数器大于3,则提示请求频繁;计数器清零,起始时间修改为当前时间* 3、超过3秒,计数器小于3,计数器清零,起始时间修改为当前时间*/

11-04 接口缓存问题处理(开发egg-interfaceCache插件)

一、缓存接口思路

/** 缓存接口* 1、接口地址作为redis中的key* 2、查询redis, 有缓存、返回返回接口* 3、没有缓存,将接口返回结果保存到redis中*/

二、缓存的接口:比如用户详情接口

第12章 项目部署

12-01 Docker简介

一、为什么需要Docker

1、开发环境不一致:开发系统不一致、本地开发环境和线上环境不同

线上环境一般是linux系统

2、软件安装麻烦:安装不同软件的复杂程度不同,不仅耗时久还容易出错。

3、运维成本过高:软件维护和升级都比较费时费力,如果新增机器,所有软件都需要重新安装

二、docker官网:/get-docker/

12-02 Docker基础入门

一、Docker操作

1、镜像操作:拉取、查看、删除等

2、容器操作:运行、查看、进入、删除等

二、Docker engine

1、docker引擎的镜像:https://register.docker-,默认是国外的,可以设置成这个国内的

https://hub.daocloud.io,国内的镜像

2、docker pull daocloud.io/library/node:12.18

docker images

docker tag 28faf336034d node

docker tag 28faf336034d node1:v1.0

3、导出镜像

mkdir docker

cd docker

ls

docker save -o node.image 28faf336034d

4、删除镜像

ls

docker rmi 28faf336034d -f

5、导入镜像

docker load -i node.image

三、本课程mysql版本:8.0.20

1、启动并运行一个镜像:run

2、docker run -d -p 3307:3306 --name mysql -e MYSQL_ROOT_PASSWORD=abc123456 be0dbf01a0f3(3306:当前启动的容器的端口)

3、docker ps

4、docker ps -a // 查看所有当前运行的/停止的镜像

5、docker stop a24c8a967dd6

6、docker rm a24c8a967dd6

7、docker exec -it ecf7f372b176 sh // 进入容器内部

mysql -uroot -p

show database

exit // 退出mysql

exit // 退出mysql容器

8、docker restart ecf7f372b176

12-03 阿里云后台介绍

一、云服务器ecs

公网ip:暴露给第三方

私有ip:当前实例中使用的,外部人员是访问不到的

二、ssh root@47.108.197.103 // 跟着的是公网ip,进入阿里云后台

三、pwd,当前路径

12-04 项目部署

一、阿里云环境下安装docker

centos

二、用yum安装docker

1、yum install yum-utils device-mapper-persistent-data lvm2

2、y

3、设置阿里的镜像源

yum-config-manager --add-repo /docker-ce/linux/centos/docker-ce.repo

4、y

5、y

6、启动docker

start docker

7、开机启动

enable docker

8、docker -v

9、修改镜像源

vi /etc/docker/daemon.json

{"registry-mirrors": ["https://register.docker-/"]}

systemct1 daemon-reload

systemct1 restart docker

三、安装镜像

1、mysql:docker pull daocloud.io/library/mysql:8.0.20

2、redis

四、本地nginx里的内容复制到阿里云,scp

scp -rp nginx root@47.108.197.103:/root

五、server/Dockerfile

# 使用node镜像FROM daocloud.io/library/node:12.18# 在容器中新建目录文件夹 eggRUN mkdir -p /egg# 将/egg设置为默认工作目录WORKDIR /egg# 将package.json 复制默认工作目录COPY package.json /egg/package.json# 安装依赖RUN yarn config set register https://registry.RUN yarn --production# 再copy代码至容器COPY ./ /egg# 7001端口EXPOSE 7001# 等容器启动之后执行脚本CMD yarn start

六、daemon可以让服务在后台运行

七、解压 unzip

unzip -u -d server egg.zip

八、docker中mysql的权限配置

1、docker exec -it fb2520649292 sh

2、mysql -uroot -p

3、远程连接授权

GRANT ALL PRIVILEGES ON.TO ‘root’@’%’ WITH GRANT OPTION

4、刷新权限

FLUSH PRIVILEGES;

5、更改加密规则

ALTER USER ‘root’@‘localhost’ IDENTIFIED BY ‘password’ PASSWORD EXPIRE NEVER;

6、更新root用户密码

ALTER USER ‘root’@’%’ IDENTIFIED WITH mysql_native_password BY ‘abc123456’;

7、刷新权限

FLUSH PRIVILEGES;

九、docker build -t egg:v1.0 ./server

docker run -d -p 7001:7001 --name server cf0aef86ed0e

docker logs -f abbfa1822b05 // abbfa1822b05是port

12-07 课程总结

一、课程主线

前端:React.js Umijs think-react-store

后端:Egg.js Mysql Redis Docker

二、分页,多表联查 egg-sequelize

【笔记-node】《Egg.js框架入门与实战》 《用 React+React Hook+Egg 造轮子 全栈开发旅游电商应用》

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。