Docker常用命令

  • 服务
1
2
# 查看Docker版本信息
docker version
  • 镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 列出镜像
docker images 或者 docker image ls
# 删除指定镜像
docker rmi <镜像Id> 或者 docker image rm <镜像Id>
# 删除所有镜像
docker rmi $(docker images -q)
# 删除所有<none>镜像
docker rmi $(docker images | grep "none" | awk '{print $3}')
# 导入镜像
docker load
# 构建镜像
docker build docker build -t [镜像自定义名称] .
# 运行镜像
docker run [镜像ID] docker run -it --name [容器自定义名称] -d [镜像名称]:latest
# 保存镜像到本地
docker save [镜像名称] | gzip > [保存文件名称]
# 加载本地镜像
docker load < [保存镜像文件名称]
  • 容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 列出本机运行的容器
docker ps
# 列出本机所有的容器(包括停止和运行)
docker ps -a
# 新建并启动
docker run [镜像名/镜像ID]
# 启动已终止容器
docker start [容器ID]
# 停止运行的容器
docker stop [容器ID]
# 杀死容器进程
docker kill [容器ID]
# 重启容器
docker restart [容器ID]
# 删除容器
docker rm [容器ID]
# 交互式进入容器
docker exec [容器ID]
# 导出容器
docker export [容器ID]
# 导入容器
docker import [路径]
# 查看日志
docker logs [容器ID]

服务器设置和Docker安装

服务器厂商每年都会搞促销活动,但是促销只针对新买的服务器,而之前买的服务器续费就没有促销。这样就导致,旧的服务器到期了就不能用了,上面部署的服务都要迁移到新的服务器。

服务器设置

服务器选Debian

  1. 更改root密码
1
passwd
  1. 新建用户
1
useradd -m zyf
  1. 配置免密登录
1
2
3
4
5
6
7
8
9
10
11
# 本地生成公钥、私钥
ssh-keygen -t ed25519 -f xxx_ed25519

# 在目标服务器操作, 复制生成的公钥
vi /home/zyf/.ssh/authorized_keys

chown -R zyf:zyf /home/zyf/.ssh

chmod 700 /home/zyf/.ssh
chmod 600 /home/zyf/.ssh/authorized_keys

  1. 禁用密码登录和root登录
1
2
3
4
5
6
7
vi /etc/ssh/sshd_config
# 禁止root登录 PermitRootLogin yes改成no
# 禁止密码登录 PasswordAuthentication yes改为no
# 启用密钥验证 RSAAuthentication yes

# 重启sshd服务
systemctl restart sshd

Docker 安装

  1. 注册源
1
2
3
4
5
6
7
8
9
10
11
12
13
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
  1. 安装
1
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

gitea的docker安装

Gitea是一个自己托管的 Git 服务程序。他和GitHub, BitbucketGitlab等比较类似。他是从Gogs 发展而来,Gitea的首要目标是创建一个极易安装,运行非常快速,安装和使用体验良好的自建 Git 服务。

安装 docker-compose

Gitea在其Docker Hub组织内提供自动更新的Docker镜像。可以始终使用最新的稳定标签或使用其他服务来更新Docker镜像。

  1. 更新 apt 包索引并安装包以允许 apt 通过 HTTPS 使用存储库:
1
2
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
  1. 添加Docker的官方GPG密钥:
1
2
3
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
  1. 使用以下命令设置软件源:
1
2
3
4
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  1. 更新 apt 包索引:
1
sudo apt-get update
  1. 安装Docker EnginecontainerdDocker Compose:
1
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

基本安装

最简单的设置只是创建一个卷和一个网络,然后将gitea/gitea:latest镜像作为服务启动。创建一个类似gitea的目录,并将以下内容粘贴到名为docker-compose.yml的文件中。请注意,该卷应由配置文件中指定的UID/GID的用户/组拥有。如果您不授予卷正确的权限,则容器可能无法启动。另请注意,标签 :latest 将安装当前的开发版本。对于稳定的发行版,您可以使用 :1 或指定某个发行版,例如 1.19.0-rc1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
version: "3"

networks:
gitea:
external: false

services:
server:
image: gitea/gitea:1.19.0-rc1
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"

MySQL 数据库

要将GiteaMySQL数据库结合使用,请将这些更改应用于上面创建的docker-compose.yml文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
version: "3"

networks:
gitea:
external: false

services:
server:
image: gitea/gitea:1.19.0-rc1
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
+ - GITEA__database__DB_TYPE=mysql
+ - GITEA__database__HOST=db:3306
+ - GITEA__database__NAME=gitea
+ - GITEA__database__USER=gitea
+ - GITEA__database__PASSWD=gitea
restart: always
networks:
- gitea
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
+ depends_on:
+ - db
+
+ db:
+ image: mysql:8
+ restart: always
+ environment:
+ - MYSQL_ROOT_PASSWORD=gitea
+ - MYSQL_USER=gitea
+ - MYSQL_PASSWORD=gitea
+ - MYSQL_DATABASE=gitea
+ networks:
+ - gitea
+ volumes:
+ - ./mysql:/var/lib/mysql

命名卷

要使用命名卷而不是主机卷,请在docker-compose.yml配置中定义并使用命名卷。此更改将自动创建所需的卷。您无需担心命名卷的权限;Docker将自动处理该问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
version: "3"

networks:
gitea:
external: false

+volumes:
+ gitea:
+ driver: local
+
services:
server:
image: gitea/gitea:1.19.0-rc1
container_name: gitea
restart: always
networks:
- gitea
volumes:
- - ./gitea:/data
+ - gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"

启动

要基于docker-compose启动此设置,请执行docker-compose up -d,以在后台启动Gitea。使用docker-compose ps将显示 Gitea 是否正确启动。可以使用docker-compose logs查看日志。

要关闭设置,请执行docker-compose down。这将停止并杀死容器。这些卷将仍然存在。

注意:如果在 http 上使用非 3000 端口,请更改app.ini以匹配LOCAL_ROOT_URL = http://localhost:3000/

Nodejs项目配置Typescript,Eslint,prettier等

前言

现代化的工程项目搭建,已经不仅仅满足于可以用了,更多要求规范使用。为实现这已目的,项目搭建离不开Typescript、Eslint、prettier的配置。

Nodejs项目搭建

执行npm init -y命令生产package.json文件

Typescript

  • 安装typescript
    执行命令 npm install typescript --save-dev
  • 安装@types/node
    执行命令 npm install @types/node --save-dev
  • 生成tsconfig.json文件
    执行命令 npx tsc --init,常见配置见tsconfig配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    "compilerOptions": {
    ...
    "rootDir": "./src", // 读取ts文件根目录
    "outDir": "./dist", // 生成js文件路径
    "removeComments": true, // 生成js文件时移除注释
    ...
    }
    "include": ["src"],
    "exclude": ["node_modules"]
    }
  • 安装ts-node
    执行命令 npm install ts-node --save-dev, ts-node可以运行时解析ts文件,无需转换成js运行。
  • 配置nodemon
    新建nodemon.json文件
    1
    2
    3
    4
    5
    6
    {
    "watch": ["src"],
    "ext": ".ts,.js",
    "ignore": [],
    "exec": "ts-node ./src/index.ts"
    }
    package.json中配置scripts命令
    1
    2
    3
    4
    5
    "build": "tsc",
    "prestart": "npm run build",
    "start": "node ./dist/index.js",
    "start:dev": "nodemon",
    "lint": "eslint . --ext .js,.ts"

Eslint

  • 初始化Eslint
    执行命令 npx eslint --init,然后根据自己需求选择配置
  • 配置.eslintrc.js文件
    .eslintrc.js文件是配置文件,如果某些想忽略,可以新建文件.eslintignor,写入想要忽略的文件路径

prettier

  • 安装依赖
    执行命令npm install eslint-config-prettier eslint-plugin-prettier --save-dev安装 eslint-config-prettiereslint-plugin-prettier即可
  • 修改.eslintrc.js文件
    1
    2
    3
    4
    5
    6
    7
    extends: [..., 'plugin:prettier/recommended'],
    overrides: [],
    parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
    project: './tsconfig.json',
    },
  • 常见prettier配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    module.exports = {
    // 1.一行代码的最大字符数,默认是80(printWidth: <int>)
    printWidth: 80,
    // 2.tab宽度为2空格(tabWidth: <int>)
    tabWidth: 2,
    // 3.是否使用tab来缩进,我们使用空格(useTabs: <bool>)
    useTabs: false,
    // 4.结尾是否添加分号,false的情况下只会在一些导致ASI错误的其工况下在开头加分号,我选择无分号结尾的风格(semi: <bool>)
    semi: false,
    // 5.使用单引号(singleQuote: <bool>)
    singleQuote: true,
    // 6.object对象中key值是否加引号(quoteProps: "<as-needed|consistent|preserve>")as-needed只有在需求要的情况下加引号,consistent是有一个需要引号就统一加,preserve是保留用户输入的引号
    quoteProps: 'as-needed',
    // 7.在jsx文件中的引号需要单独设置(jsxSingleQuote: <bool>)
    jsxSingleQuote: false,
    // 8.尾部逗号设置,es5是尾部逗号兼容es5,none就是没有尾部逗号,all是指所有可能的情况,需要node8和es2017以上的环境。(trailingComma: "<es5|none|all>")
    trailingComma: 'es5',
    // 9.object对象里面的key和value值和括号间的空格(bracketSpacing: <bool>)
    bracketSpacing: true,
    // 10.jsx标签多行属性写法时,尖括号是否另起一行(jsxBracketSameLine: <bool>)
    jsxBracketSameLine: false,
    // 11.箭头函数单个参数的情况是否省略括号,默认always是总是带括号(arrowParens: "<always|avoid>")
    arrowParens: 'always',
    // 12.range是format执行的范围,可以选执行一个文件的一部分,默认的设置是整个文件(rangeStart: <int> rangeEnd: <int>)
    rangeStart: 0,
    rangeEnd: Infinity,
    // 18. vue script和style标签中是否缩进,开启可能会破坏编辑器的代码折叠
    vueIndentScriptAndStyle: false,
    // 19. endOfLine: "<lf|crlf|cr|auto>" 行尾换行符,默认是lf,
    endOfLine: 'lf',
    // 20.embeddedLanguageFormatting: "off",默认是auto,控制被引号包裹的代码是否进行格式化
    embeddedLanguageFormatting: 'off',
    }

文档资料

Docker入门

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),我们用社区版就可以了。

官网文档:https://docs.docker.com/
官方仓库:https://hub.docker.com/

Docker的应用场景

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。

Dcoker基本概念

Docker 包括三个基本概念:

  • 镜像(Image):Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  • 仓库(Repository):仓库(Repository)类似Git的远程仓库,集中存放镜像文件。

Docker常用命令

https://i.imgur.com/C2xXMGj.jpg

GraphQL 入门

GraphQL

GraphQL既是一种用于API的查询语言也是一个满足你数据查询的运行时。 GraphQL对你的API中的数据提供了一套易于理解的完整描述,使得客户端能够准确地获得它需要的数据,而且没有任何冗余,也让 API 更容易地随着时间推移而演进,还能用于构建强大的开发者工具。

GraphQL官网:https://graphql.org

GraphQL中文文档:https://graphql.cn

Apollo GraphQLhttps://www.apollographql.com/docs

入门

GraphQL 是一个用于 API 的查询语言,是一个使用基于类型系统来执行查询的服务端运行时(类型系统由你的数据定义)。GraphQL 并没有和任何特定数据库或者存储引擎绑定,而是依靠你现有的代码和数据支撑。

一个 GraphQL 服务是通过定义类型和类型上的字段来创建的,然后给每个类型上的每个字段提供解析函数。例如,一个 GraphQL 服务告诉我们当前登录用户是 me,这个用户的名称可能像这样:

1
2
3
4
5
6
7
8
type Query {
me: User
}

type User {
id: ID
name: String
}

一并的还有每个类型上字段的解析函数:

1
2
3
4
5
6
7
function Query_me(request) {
return request.auth.user;
}

function User_name(user) {
return user.getName();
}

一旦一个 GraphQL 服务运行起来(通常在 web 服务的一个 URL 上),它就能接收 GraphQL 查询,并验证和执行。接收到的查询首先会被检查确保它只引用了已定义的类型和字段,然后运行指定的解析函数来生成结果。
例如这个查询:

1
2
3
4
5
{
me {
name
}
}

会产生这样的JSON结果:

1
2
3
4
5
{
"me": {
"name": "Luke Skywalker"
}
}

Redux简介

Redux

Redux 是 JavaScript 状态容器,提供可预测化的状态管理。

Redux官网:https://redux.js.org/

Redux中文文档:https://cn.redux.js.org/

react-redux官网:https://react-redux.js.org/

Redux视频:https://egghead.io/courses/getting-started-with-redux

Provide

全局引入react-redux

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react'
import ReactDOM from 'react-dom'

import { Provider } from 'react-redux'
import store from './store'

import App from './App'

const rootElement = document.getElementById('root')
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
)

connect

组件中使用react-redux

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { connect } from 'react-redux'
import { increment, decrement, reset } from './actionCreators'

// const Counter = ...

const mapStateToProps = (state /*, ownProps*/) => {
return {
counter: state.counter
}
}

const mapDispatchToProps = { increment, decrement, reset }

export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter)

redux-thunk

redux-thunk就是redux的中间件,中间件就是你可以在收到请求和返回请求之间做一些操作。

github地址:https://github.com/reduxjs/redux-thunk

用法,在store.js文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducers';

const initializeStore = (initialState = {}) => createStore(
reducer,
initialState,
process.env.NODE_ENV === 'production'
? applyMiddleware(thunkMiddleware)
: composeWithDevTools(applyMiddleware(thunkMiddleware)),
);

export default initializeStore;

redux-thunk最重要的思想,就是可以接受一个返回函数的action creator。如果这个action creator 返回的是一个函数,就执行它,如果不是,就按照原来的next(action)执行。

1
2
3
4
5
6
7
8
9
10
11
export function addCount() {
return {type: ADD_COUNT}
}

export function addCountAsync() {
return dispatch => {
setTimeout( () => {
dispatch(addCount())
},2000)
}
}

Hooks

useSelector

基本用法:

1
2
3
4
5
6
7
import React from 'react'
import { useSelector } from 'react-redux'

export const CounterComponent = () => {
const counter = useSelector(state => state.counter)
return <div>{counter}</div>
}

useDispatch

基本用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react'
import { useDispatch } from 'react-redux'

export const CounterComponent = ({ value }) => {
const dispatch = useDispatch()

return (
<div>
<span>{value}</span>
<button onClick={() => dispatch({ type: 'increment-counter' })}>
Increment counter
</button>
</div>
)
}

Nextjs简介

Nextjs

next.js是一个非常棒的轻量级的react同构框架,使用它可以快速的开发出基于服务端渲染的react应用。

Nextjs官网:https://nextjs.org/

Nextjs官方demo:https://github.com/zeit/next.js/tree/canary/examples

Nextjs中文文档:https://nextjs.frontendx.cn/

路由处理

官方文档:https://nextjs.org/docs#routing

页面中直接跳转用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Link from 'next/link'

function Home() {
return (
<>
<ul>
<li>Home</li>
<li>
<Link href="/about">
<a>About Us</a>
</Link>
</li>
</ul>

<h1>This is our homepage.</h1>
</>
)
}

export default Home

js方法中跳转:

1
2
3
4
5
6
7
8
9
10
11
import Router from 'next/router'

function ReadMore() {
return (
<div>
Click <span onClick={() => Router.push('/about')}>here</span> to read more
</div>
)
}

export default ReadMore

Dynamic Import

官方文档:https://nextjs.org/docs#dynamic-import

因为Nextjs代码跑起来会走两套环境,分别是客户端和服务端环境,客户端环境和常规react开发一样,服务端环境就比较麻烦,windowlocalStoragenavigator.userAgent这些就会在服务端报undefined错误。所以需要控制好代码有哪些是在两个环境通用,哪些只能在客户端环境运行。

比较常见的就是视频播放,视频播放器即不需要也没办法在服务端渲染,那么如何控制它只在客户端渲染?Nextjs提供了Dynamic Import方法来处理该问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import dynamic from 'next/dynamic'

const DynamicComponentWithNoSSR = dynamic(
() => import('../components/hello3'),
{ ssr: false }
)

function Home() {
return (
<div>
<Header />
<DynamicComponentWithNoSSR />
<p>HOME PAGE is here!</p>
</div>
)
}

export default Home

自定义配置

官方文档:https://nextjs.org/docs#custom-configuration

Callback,Promise和Async/Await

JavaScript是单线程语言,但是js中有很多任务耗时比较长,比如ajax请求,如果都按照顺序进行,往往会出现浏览器无响应的情况,所以就需要异步的形式。JS中所有的任务可以分为两种:同步任务和异步任务。

  • 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;

  • 异步任务:不进入主线程,而进入任务队列中的任务,只有任务队列通知主线程,某个异步任务可以执行了,这个任务才会进入主线程执行。

  • 事件循环(Event Loop):只有执行栈中的所有同步任务都执行完毕,系统才会读取任务队列,看看里面的异步任务哪些可以执行,然后那些对应的异步任务,结束等待状态,进入执行栈,开始执行。

CallBack

回调函数本身是我们约定俗成的一种叫法,我们定义它,但是并不会立即执行它,它最终在其他地方执行了。

  • 优点:比较容易理解;
  • 缺点:1.高耦合,维护困难,回调地狱; 2.每个任务只能指定一个回调函数; 3.如果几个异步操作之间并没有顺序之分,同样也要等待上一个操作执行结束再进行下一个操作。

回调地狱:

Promise

promise对象的构造函数语法为:

1
2
3
let promise = new Promise(function(resolve, reject) {
// executor (the producing code, "singer")
});

它的参数resolvereject是JavaScript本身提供的回调。我们的代码仅在执行程序内部。当代码执行完后,它应用调用以下回调之一:

  • resolve(value)—如果成功完成,结果为value。
  • reject(error)—如果发生错误,error则是错误对象。
Promise.then .catch .finally

Promise.then相当于执行callback,不过比起callback的嵌套模式,Promise.then().then().then()...的链式写法看起来更直观和美观。

catchfinally的用法相当于try...catch...finally

Async/Await

假如,一个页面中的很多方法都依赖于一个异步函数值的结果,又不想把写好的许多方法放到Promise.the中处理,这个时候你急切得需要一个把异步函数转换成同步函数处理的方式,这个时候async/await方法应运而生。

1
2
3
4
5
6
7
8
9
let promise = new Promise(function(resolve, reject) {
// executor (the producing code, "singer")
});
promise.then(res => {
const { data } = res;
....
}).catch(err => {
console.log(errr);
})

等价于

1
2
3
4
5
6
7
8
9
10
async function do() {
try {
const res = await promise();
const { data } = res;
...
} catch(err){
console.log(errr);
}
}

PWA实战(4)—Notification

推送通知 ( Push Notification )或者也可以称作推播,有智慧手机的人我想应该非常熟悉,尤其是App盛行的时期几乎每只App都会有推送通知功能,这也是恶梦的开始,你会发觉在大半夜里你的手机会三不五时地叫你起床,所以现在的手机几乎都内建了勿扰模式,让使用者可以设定每天的某个时段可以封锁特定的讯息通知,甚至现在的系统都可以让使用用决定App允许那些权限。

推送通知就像一把双刃剑,懂得善用它可以提升用户体验,反之,若滥用它则会让使用者观感不好。

体验pwa推送

这个网站可以让你体验一下pwa推送,可以在pc和手机上分别体验。
链接:https://web-push-book.gauntface.com/demos/notification-examples/

推送通知条款

  • 通知 - 在应用程序的普通用户界面(即浏览器)之外向用户显示的消息
  • 推送消息 - 从服务器发送到客户端的消息
  • 推送通知 - 响应推送消息而创建的通知
  • 通知API - 用于配置和向用户显示通知的界面
  • Push API - 用于将应用程序订阅到推送服务并在服务工作者中接收推送消息的接口
  • Web Push - 一个非正式术语,指的是将消息从服​​务器推送到Web上的客户端过程中涉及的过程或组件
  • 推送服务 - 用于将推送消息从服务器路由到客户端的系统。每个浏览器都实现自己的推送服务。
  • Web推送协议 - 描述应用程序服务器或用户代理如何与推送服务交互

实战操作

参考链接:https://developers.google.com/web/fundamentals/codelabs/push-notifications/?hl=zh-cn

练习源码:

1
git clone https://github.com/GoogleChrome/push-notifications.git

模拟推送服务器:https://web-push-codelab.glitch.me/

推送服务

实际应用中,需要搭建推送服务负责想客户端推送消息
网络推送库:https://github.com/web-push-libs/
nodejs使用的web-push库:https://www.npmjs.com/package/web-push

关于墙的问题

推送服务的流程类似于,自己搭建的推送服务发送通知到浏览器厂商搭建的推送服务,浏览器厂商搭建的推送服务识别后发送到对应的浏览器客户端。这个过程依赖浏览器厂商搭建的推送服务。目前对pwa推送规范支持最好的有chrom浏览器和firefox浏览器,因为墙的原因,chrome浏览器的推送服务无法送达,但firefox没有任何问题。所以想使用pwa推送的话,建议用户使用firefox浏览器就可以了。