9-22
1 刷新组件的常规写法
const [, refresh] = useState<number>(0)
refresh((i) => i + 1)
2 Error: network does not support ENS
可能原因:
- 地址错误,注意地址中可能带有特殊字符,而在vscode中无法显示出来
3 测试入门
测什么?重点关注什么?
4 jest如何测试Promise
将promise返回,即可让jest等待promise结果
import { getLiquidityList } from './api'
describe('测试网络请求', () => {
it('测试能否调通Api', () => {
return getLiquidityList()
.then((res) => {
// console.log('[res]:', res)
expect(res.code).toBe(0)
expect(Object.keys(res.data).length).toBeGreaterThanOrEqual(0)
})
.catch((err) => {
console.log('[err]:', err)
})
})
})
[1] jest测试异步代码.https://jestjs.io/zh-Hans/docs/asynchronous
5 图片加载失败,备用方案
const src: string | undefined = srcs.find((src) => !BAD_SRCS[src])
if (src) {
return (
<img
{...rest}
alt={alt}
src={src}
style={style}
//重点,出错后将当前url列入黑名单
onError={() => {
if (src) BAD_SRCS[src] = true
refresh((i) => i + 1)
}}
/>
)
}
6 如何用transform: scale()来模拟zoom?
zoom只会放大内部,而scale会将整个元素放大
const scaleRate = (1920-240) / (1440 - 240) = 1.15
// 放大比例
const Content = styled(Layoutd.Content)<{ screenWidth: number | undefined }>`
/* 将整个内容区放大1.15倍 */
transform: scale(${scaleRate});
transform-origin: 0 0;
/* 修正因放大而导致的宽度变大,思路:在放大前,先将当前内容宽度去除以比例,
放大后的值与当前值是一致的,也就是宽度不变,而其他值变大了
*/
width: ${({ screenWidth }) =>
screenWidth ? ((screenWidth - 240) / scaleRate - ((scrollbarWidth() ?? 2) - 2)).toFixed() + 'px' : '100%'};
/* 内容宽度 / 比例 - 导航条宽度 */
/* 2为导航条修正偏差值 */
/*
transform已知问题:如果分辨率过大(1805以上),
会导致右下角出现1-2px的白框
*/
/* zoom也可以解决此问题,但不兼容firefox */
/* zoom: 1.2; */
/*
* 已解决以下问题。2021-09-24 16:42:20
* 缩放1.2倍,由于失误将1920设计稿用1440的方式实现,
* 现需要放大1.2倍
*
* 已知问题:
* 火狐不支持zoom,但transform:scale()无法达到想要的效果,未找到合适的解决方案
*
* 带来后果:火狐浏览器用户看到的右边内容区会比Chrome浏览器看到的小1.2倍
* 其他用户不受影响
*/
/* 在H5端修改回来 */
@media (max-width: ${MEDIUM}) {
transform: none;
width: inherit;
}
`
// 获取导航条宽度
export function scrollbarWidth() {
const cWidth = document.body.clientWidth || document.documentElement.clientWidth //页面可视区域宽度
const iWidth = window.innerWidth //浏览器窗口大小
if (!iWidth || !cWidth) return undefined
console.log('[](iWidth - cWidth):', iWidth - cWidth, iWidth, cWidth)
return iWidth - cWidth
}
7 验证数字和小数点
export function validaInputValue(value: string | undefined) {
if (value) {
// 只要数字和小数点
if (!value.match(/^[\d\.]+$/g)) throw new Error('只要数字和小数点')
// 只要一个小数点
const hasOnlyOnePoint = value.match(/\./g)
if (hasOnlyOnePoint && hasOnlyOnePoint.length > 1) throw new Error('只要一个小数点')
}
}
9 web3-react连接流程
import React, { useState, useEffect } from 'react'
import { useWeb3React } from '@web3-react/core'
import styled from 'styled-components/macro'
import { network } from '../../connectors'
import { useEagerConnect, useInactiveListener } from '../../hooks/web3'
import { NetworkContextName } from '../../constants/misc'
import Loader from '../Loader'
const MessageWrapper = styled.div`
display: flex;
align-items: center;
justify-content: center;
height: 20rem;
`
const Message = styled.h2`
color: ${({ theme }) => theme.secondary1};
`
export default function Web3ReactManager({ children }: { children: JSX.Element }) {
const { active } = useWeb3React()
const { active: networkActive, error: networkError, activate: activateNetwork } = useWeb3React(NetworkContextName)
// try to eagerly connect to an injected provider, if it exists and has granted access already
const triedEager = useEagerConnect()
// after eagerly trying injected, if the network connect ever isn't active or in an error state, activate itd
useEffect(() => {
if (triedEager && !networkActive && !networkError && !active) {
activateNetwork(network)
}
}, [triedEager, networkActive, networkError, activateNetwork, active])
// when there's no account connected, react to logins (broadly speaking) on the injected provider, if it exists
useInactiveListener(!triedEager)
// handle delayed loader state
const [showLoader, setShowLoader] = useState(false)
useEffect(() => {
const timeout = setTimeout(() => {
setShowLoader(true)
}, 600)
return () => {
clearTimeout(timeout)
}
}, [])
// on page load, do nothing until we've tried to connect to the injected connector
if (!triedEager) {
return null
}
// if the account context isn't active, and there's an error on the network context, it's an irrecoverable error
if (!active && networkError) {
return (
<MessageWrapper>
<Message>
Oops! An unknown error occurred. Please refresh the page, or visit from another browser or device.
</Message>
</MessageWrapper>
)
}
// if neither context is active, spin
if (!active && !networkActive) {
return showLoader ? (
<MessageWrapper>
<Loader />
</MessageWrapper>
) : null
}
return children
}
上面是整个连接节点的代码,总共有以下几步:
第一步:尝试积极的连接(通过injected去连接)
例如:metamask注入的web3
第二步:尝试http连接(通过http去连接)
例如:https://arb1.arbitrum.io/rpc
第三步:在连接前的监听事件
通过下面两个事件实现:链改变、账户改变
ethereum.on('chainChanged', handleChainChanged)
ethereum.on('accountsChanged', handleAccountsChanged)
我们知道在有注入ethereum的时候,可以通过eth...去监听状态,那么通过http连接的呢?
问题1:web3和etherjs区别?
都是获取chain数据的js库,只不过各有特点,web3较早,维护人员稳定一些,使用者更多一些
问题2:连接节点和getLibrary有什么关系?
连接上了节点之后,就需要一个Provider提供服务(方法),例如:获取账户余额,获取区块信息等,其实library在etherjs中已经提供了,只不过可以将它进一步包装,例如:Web3Provider,JsonRpcProvider等,这样能够方便的调用其方法
10 v2ray可以调整模式
调整模式为指定IP地址才科学上网
可以在 pac.js
中指定需要科学上网的IP地址(域名)
11 在react中判断是否为手机端的方法
import { isMobile } from 'react-device-detect'
https://www.npmjs.com/package/react-device-detect
12 前端连接钱包所需要的库
总的来说,需要两个库:etherjs或者web3js
和 web3-react
etherjs提供底层的服务,而web3-react提供react方面的应用层服务(通过hooks访问数据,连接钱包等)
问题1:web3-react提供连接服务,那么原始通过web3去调用方法和连接合约是可以直接操作的,那么web3-react为什么要多做一次操作?
因为这样可以控制连接,例如:控制连接支持的网络
问题2:web3-react中如何连接合约呢?
通过实例化etherjs的Contract来连接合约,而实例化的时候可选是否传入签名
13 显示点点点-动画
export const Dots = styled.span`
&::after {
display: inline-block;
animation: ellipsis 1.25s infinite;
content: '.';
width: 1em;
text-align: left;
}
@keyframes ellipsis {
0% {
content: '.';
}
33% {
content: '..';
}
66% {
content: '...';
}
}
`
14 react单元测试和组件测试
最近在看《持续交付2.0》这本书,里面讲到了测试用例集,书中说讲的基本都是C++、JAVA等项目的测试用例,基本都是同步的,但是我在思考,我们前端大量的异步代码如何进行测试?组件的生命周期、事件如何测试?
这两篇文章值得参考一下:
那些年错过的React组件单元测试(上).https://segmentfault.com/a/1190000039710016那些年错过的React组件单元测试(下).https://segmentfault.com/a/1190000039754477
以上两篇文章并不适用于函数式组件,react16.8以上请使用官方推荐的 React Testing Library
问题1: React Testing Library与jest的区别?各自适用于什么情况呢?
目前,我认为 jest
是一个测试库,而 React Testing Library
是一个测试工具集,它提供各种工具去测试,React Testing Library是依赖于jest的
react组件测试
使用React Testing Library进行组件测试的 AAA模式
:编排(Arrange),执行(Act),断言(Assert)。
编排
在编排这一步,我们需要完成2项任务:
- 渲染组件
- 获取所需的DOM的不同元素。
function render(
ui: React.ReactElement,
options?: Omit<RenderOptions, 'queries'>
): RenderResult
上面是render函数的定义
const instance = render(<Counter />);
// OR
const { getByText, queryByText } = render(<Counter />);
// get* 查找text的元素,找不到报错
// query* 查找text的元素,找不到返回null
执行
触发相应的事件
fireEvent.click(incrementButton);
// OR
fireEvent.click(decrementButton);
断言
expect(counter.textContent).toEqual("1");
expect(counter.textContent).toEqual("0");
// 通过节点去查询元素
expect(instance.getByText('123')).toBeInTheDocument()
// 当然也可以通过屏幕去查询
expect(screen.getByText('123')).toBeInTheDocument()
[1] 使用 React Testing Library 和 Jest 完成单元测试.https://juejin.cn/post/6844904101730320397
示例-摘抄自 React Testing Library 文档
// Login/index.tsx
import * as React from 'react'
interface State {
resolved: boolean
loading: boolean
error: string | null
}
const initState : State = {
resolved: false,
loading: false,
error: null,
}
function Login() {
// 看不懂这个s,a的请看(state, action) => newState
const [state, setState] = React.useReducer((s: State, a: any) => ({...s, ...a}), initState)
function handleSubmit(event: any) {
event.preventDefault()
const {usernameInput, passwordInput} = event.target?.elements
setState({loading: true, resolved: false, error: null})
window
.fetch('/api/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: usernameInput.value,
password: passwordInput.value,
}),
})
.then(r => r.json().then(data => (r.ok ? data : Promise.reject(data))))
.then(
user => {
setState({loading: false, resolved: true, error: null})
window.localStorage.setItem('token', user.token)
},
error => {
setState({loading: false, resolved: false, error: error.message})
},
)
}
return (
<div>
<form onSubmit={handleSubmit}>
<div>
<label htmlFor="usernameInput">Username</label>
<input id="usernameInput" />
</div>
<div>
<label htmlFor="passwordInput">Password</label>
<input id="passwordInput" type="password" />
</div>
<button type="submit">Submit{state.loading ? '...' : null}</button>
</form>
{state.error ? <div role="alert">{state.error}</div> : null}
{state.resolved ? (
<div role="alert">Congrats! You're signed in!</div>
) : null}
</div>
)
}
export default Login
// Login/index.test.tsx
import '@testing-library/jest-dom'
import * as React from 'react'
// import API mocking utilities from Mock Service Worker.
import {rest} from 'msw'
import {setupServer} from 'msw/node'
// import testing utilities
import {render, fireEvent, screen} from '@testing-library/react'
import Login from './index'
const fakeUserResponse = {token: 'fake_user_token'}
const server = setupServer(
rest.post('/api/login', (req, res, ctx) => {
return res(ctx.json(fakeUserResponse))
}),
)
beforeAll(() => server.listen())
afterEach(() => {
server.resetHandlers()
window.localStorage.removeItem('token')
})
afterAll(() => server.close())
test('allows the user to login successfully', async () => {
render(<Login />)
// fill out the form
fireEvent.change(screen.getByLabelText(/username/i), {
target: {value: 'chuck'},
})
fireEvent.change(screen.getByLabelText(/password/i), {
target: {value: 'norris'},
})
fireEvent.click(screen.getByText(/submit/i))
// just like a manual tester, we'll instruct our test to wait for the alert
// to show up before continuing with our assertions.
const alert = await screen.findByRole('alert')
// .toHaveTextContent() comes from jest-dom's assertions
// otherwise you could use expect(alert.textContent).toMatch(/congrats/i)
// but jest-dom will give you better error messages which is why it's recommended
expect(alert).toHaveTextContent(/congrats/i)
expect(window.localStorage.getItem('token')).toEqual(fakeUserResponse.token)
})
test('handles server exceptions', async () => {
// mock the server error response for this test suite only.
server.use(
rest.post('/api/login', (req, res, ctx) => {
return res(ctx.status(500), ctx.json({message: 'Internal server error'}))
}),
)
render(<Login />)
// fill out the form
fireEvent.change(screen.getByLabelText(/username/i), {
target: {value: 'chuck'},
})
fireEvent.change(screen.getByLabelText(/password/i), {
target: {value: 'norris'},
})
fireEvent.click(screen.getByText(/submit/i))
// wait for the error message
const alert = await screen.findByRole('alert')
expect(alert).toHaveTextContent(/internal server error/i)
expect(window.localStorage.getItem('token')).toBeNull()
})
msw库
在上一节组件测试中用到了msw,msw是一个用于mock数据的库,但它是真正开启了服务的,文档写的很好,还有互动
// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
// This configures a request mocking server with the given request handlers.
// 融合
export const server = setupServer(...handlers)
// src/mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.post('/login', (req, res, ctx) => {
// Persist user's authentication in the session
sessionStorage.setItem('is-authenticated', 'true')
return res(
// Respond with a 200 status code
ctx.status(200),
)
}),
rest.get('/user', (req, res, ctx) => {
// Check if the user is authenticated in this session
const isAuthenticated = sessionStorage.getItem('is-authenticated')
if (!isAuthenticated) {
// If not authenticated, respond with a 403 error
return res(
ctx.status(403),
ctx.json({
errorMessage: 'Not authorized',
}),
)
}
// If authenticated, return a mocked user details
return res(
ctx.status(200),
ctx.json({
username: 'admin',
}),
)
}),
]
上面两步已经将server配置好了接口,接下来在测试中使用server
// src/setupTests.js
import { server } from './mocks/server.js'
// Establish API mocking before all tests.
beforeAll(() => server.listen())
// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers())
// Clean up after the tests are finished.
afterAll(() => server.close())
15 mac上的状态栏网速
Stats软件.https://github.com/exelban/stats
16 docker下载镜像太慢的解决方案
思路:利用阿里云的镜像加速服务-free
[1] docker下载镜像太慢的解决方案.https://blog.csdn.net/weixin_43569697/article/details/89279225
17 使用docker创建一个ubuntu20.04
❌ 意义不大,各种限制,特别是网络方面
转载:https://zhuanlan.zhihu.com/p/59548929
原文:https://blog.smslit.cn/2018/12/20/docker_ubuntu_learn/
大致步骤:拉取ubuntu镜像-> 启动镜像容器-> 安装需要的软件(vim、ssh服务端),并进行相关配置-> commit形成自己的镜像-> 启动自己的镜像容器-> 客户端通过ssh访问
如何创建快捷ssh?
为了更方便的连接,可以为容器创建 ssh 连接的主机短名,往 macOS 的 ~/.ssh/config
中添加以下内容:
Host learn
HostName localhost
User root
Port 26122
此时就可以通过命令 ssh learn
连接 ubuntu 容器 learn 了。
18 Github Actions
⚠️ GithubActions的自动化脚本基本上google一下都能找到相似的,修改修改就可以使用,不用专研过深
[1] GitHub Actions 入门教程.https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html
[2] Actions Market.https://github.com/marketplace?type=actions
19 ssh-scp带端口参数怎么办
#注意是大写P
scp -P 4588 [email protected]:/usr/local/sin.sh /home/administrator
#注意是小写p
ssh [email protected] -p 16112
20 自动化部署-连接远端服务器脚本
#!/bin/sh
eval $(ssh-agent -s)
#将ssh private key 放入当前服务器,这样才可以登录远端服务器
#注意加上""双引号
echo "$PRIVATE_KEY" > deploy.key
mkdir -p ~/.ssh
chmod 0600 deploy.key
ssh-add deploy.key
echo "Host *\n\tStrictHostKeyChecking no\n\n" >> ~/.ssh/config
#复制一些东西
scp sh/deploy_dev_docker_pull.sh $HOST_NAME_15@$ADMIN_HOST_15:~/sh/
scp docker-compose-dev.yml $HOST_NAME_15@$ADMIN_HOST_15:~/sh/
#登录远端服务器并执行命令
ssh $HOST_NAME_15@$ADMIN_HOST_15 "cd sh && sh deploy_dev_docker_pull.sh"
⚠️ 注意:需在GithubActions的脚本中声明$PRIVATE_KEY、$HOST_NAME_15、$ADMIN_HOST_15等变量,例如:
#build_dev.yml
env:
DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }}
DOCKER_ACCESS_NAME: ${{ secrets.DOCKER_ACCESS_NAME }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
HOST_NAME_15: ${{ secrets.HOST_NAME_15 }}
ADMIN_HOST_15: ${{ secrets.ADMIN_HOST_15 }}
有几点需要说明:
ssh-add
ssh-add可以将private key添加到ssh-agent高速缓存区,这样就可以无需密码去连接服务器
注意文件权限为0600
1、把专用密钥添加到 ssh-agent 的高速缓存中:
ssh-add ~/.ssh/id_dsa
2、从ssh-agent中删除密钥:
ssh-add -d ~/.ssh/id_xxx.pub
3、查看ssh-agent中的密钥:
ssh-add -l
scp
scp可以将文件(目录-r)在两个服务器之间拷贝
scp -P 123 path target:path
例子:
scp -P 22 ./a.txt [email protected]:~/a.txt
21 Github Action 如果要设置多个触发方式
如果没有具体配置,则用多个数组:
on: [push, workflow_dispatch]
如果有一个配置,而另一个没有,则留空:
# 第一个留空就好,注意尾部冒号
on:
workflow_dispatch:
push:
branches:
- main
22 给服务器添加公匙-服务器免密登录
第一步:通过密码登录服务器
ssh 192.168.2.31 -l root
第二步:ssh-keygen
一路回车
ssh-keygen
第三步:登录远端服务器,并将用户公匙添加到authorized_keys
vim ~/.ssh/authorized_keys
[1] Linux 添加ssh公钥.https://blog.csdn.net/qq_24909089/article/details/81231373
问题1:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
解决方案:删除~/.ssh/known_hosts
,并重新尝试链接
rm ~/.ssh/known_hosts
ssh [email protected]
# 回车后输入yes
[1] 关于ssh登录出现异常警告:WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!.https://www.cnblogs.com/johnchain/archive/2013/04/08/3006631.html
问题2:如何生成私匙和公匙?
ssh-keygen -t rsa -C "您的邮箱地址"
一路回车
23 Github Action docker login报错-docker login can not perform an interactive login from a non TTY
命令如下:
docker login -u $DOCKER_ACCESS_KEY -p $DOCKER_ACCESS_TOKEN
报错,如果改成如下:则通过
docker login -u "$DOCKER_ACCESS_KEY" -p "$DOCKER_ACCESS_TOKEN"
24 docker push的时候-denied: requested access to the resource is denied
原因:极大可能是没有登录成功,尽管docker提示 Login success
在github action的yaml配置中,一定要检查环境变量是否生效
echo "检查是否有DOCKER_ACCESS_KEY环境变量"
echo "--------$DOCKER_ACCESS_KEY-------------/n"
=>输出***就表示可以访问
--------***-------------
在sh文件中是无法拿到github配置的环境变量,要访问只能通过yaml配置文件重新声明一下:
name: deploy dev to nginx
on:
workflow_dispatch:
push:
branches:
- main
env:
# 中转环境变量
DOCKER_ACCESS_KEY: ${{secrets.DOCKER_ACCESS_KEY}}
DOCKER_ACCESS_TOKEN: ${{secrets.DOCKER_ACCESS_TOKEN}}
这样就能够在sh文件中访问声明的环境变量
docker login --username "$DOCKER_ACCESS_KEY" -p "$DOCKER_ACCESS_TOKEN"
官网也有介绍,所以要多看看文档
Example using Bash
steps:
- shell: bash
env:
SUPER_SECRET: ${{ secrets.SuperSecret }}
run: |
example-command "$SUPER_SECRET"
https://docs.github.com/en/actions/security-guides/encrypted-secrets
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=arm64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get install docker-ce="5:20.10.8~3-0~ubuntu-focal" docker-ce-cli="5:20.10.8~3-0~ubuntu-focal" containerd.io
部署时,链接远端服务器需要配置deploy.key的注意
注意,private key一定要复制完全,头部、尾部都要复制进去,否则提示 format invalid
正确例子:
-----BEGIN OPENSSH PRIVATE KEY-----
b3Bl*********************kCZ0FXwcj
nxr5EMiLZX/qUAAAAPZ2lubGlua0AxNjMuY29tAQIDBA==
-----END OPENSSH PRIVATE KEY-----
25 docker中安装docker
总结
docker中安装docker有许多问题,不建议使用
docker in docker
目前只能通过 docker:dind
安装容器中的容器,其他如ubuntu-dind等都无法在容器中使用docker
docker run -d --name dind --privileged docker:dind # 启动容器
$ docker logs -f dind # 查看启动日志
$ docker exec -it dind sh # 进入容器
说明:docker:dind中安装的是 alpine linux
,包管理器为apk
[1] docker:latest 和 docker:dind 镜像区别.https://segmentfault.com/a/1190000025133926
Apk常用命令有
# 安装
add:命令从仓库中安装最新软件包,并自动安装必须的依赖包,也可以从第三方仓库添加软件包。add:安装PACKAGES并自动解决依赖关系。
apk add openssh openntp vim
apk add --no-cache mysql-client
apk add docker --update-cache --repository http://mirrors.ustc.edu.cn/alpine/v3.4/main/ --allow-untrusted
# 安装指定版本软件包
apk add asterisk=1.6.0.21-r0
apk add 'asterisk<1.6.1'
apk add 'asterisk>1.6.1
# 卸载
del:卸载并删除PACKAGES
apk del openssh openntp vim
# 升级
upgrade命令升级系统已安装的所以软件包(一般包括内核),当然也可指定仅升级部分软件包(通过-u或–upgrade选择指定)。
apk update #更新最新本地镜像源
apk upgrade #升级软件
# 搜索
search命令搜索可用软件包,-v参数输出描述内容,支出通配符,-d或–description参数指定通过软件包描述查询。
apk search #查找所以可用软件包
# 查看包信息
info命令用于显示软件包的信息。
apk info #列出所有已安装的软件包
实例:安装一个bash,并配置
配置国内源
sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
安装
apk update
apk upgrade
apk add vim bash bash-doc bash-completion
vim ~/.bashrc
# 输入以下内容
alias update='apk update && apk upgrade'
export HISTTIMEFORMAT="%d/%m/%y %T "
export PS1='\u@\h:\W \$ '
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
source /etc/profile.d/bash_completion.sh
[1] 在 Alpine Linux 中安装 bash shell.https://www.oschina.net/translate/alpine-linux-install-bash-using-apk-command
[2] alpine linux更新国内源.https://blog.csdn.net/vah101/article/details/108602970
[3] alpine Linux-apk软件包管理器,就这么用.https://blog.csdn.net/hxpjava1/article/details/80221307
26 Docker删除所有容器
删除所有容器
docker rm `docker ps -a -q`
docker rm 'docker ps -a -q'
删除所有镜像
docker rmi `docker images -q`
27 Mac docker无法连接容器IP的问题
问题描述:能够通过 docker inspect查看容器的IP地址,但是无法ping通,所以无法访问里面的服务
解决方案:端口映射
docker run -d -p 7500-7550:7500-7550 --name dind8 --privileged docker:dind
注意:端口不要范围不要太宽,否则会导致失败
重新启动exit状态的容器
docker ps -a #查看所有容器,找到要重启的容器ID
docker start 容器ID
关闭容器
docker stop 容器ID或容器名
# OR
docker kill 容器ID或容器名
stop和kill的主要区别:stop给与一定的关闭时间交由容器自己保存状态,kill直接关闭容器
[1] Mac系统下docker容器无法使用--net host共享宿主机端口的解决方案.https://blog.csdn.net/qq_42937522/article/details/109052954
28 给alpine安装sshd
apk update && \
apk add --no-cache openssh tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
sed -i "s/#PermitRootLogin.*/PermitRootLogin yes/g" /etc/ssh/sshd_config && \
ssh-keygen -t dsa -P "" -f /etc/ssh/ssh_host_dsa_key && \
ssh-keygen -t rsa -P "" -f /etc/ssh/ssh_host_rsa_key && \
ssh-keygen -t ecdsa -P "" -f /etc/ssh/ssh_host_ecdsa_key && \
ssh-keygen -t ed25519 -P "" -f /etc/ssh/ssh_host_ed25519_key && \
echo "root:admin" | chpasswd
启动
/usr/sbin/sshd -D
修改ssh的端口
第一步:打开配置文件,修改为需要的端口
vim /etc/ssh/sshd_config
# 例如修改为7501端口
port 7501
第二步:重启sshd
/etc/init.d/sshd restart
[1] alpine安装sshd/ssh server(通过Dockerfile配置).https://www.cnblogs.com/sunsky303/p/11543747.html
[2] linux修改ssh端口.https://www.jianshu.com/p/7c4ffbc8927a
29 给Alpine linux设置环境变量
vim ~/.bashrc
# 设置环境变量
export DOCKER_ACCESS_KEY="demo"
export DOCKER_ACCESS_TOKEN="d9999994-40006b-41223a6-a102-5d88888888e0"
source ~/.bashrc
30 dcoker-compose基本用法
启动所有服务
docker-compose -f compose-file.yml up -d
# -d后台运行
关闭所有服务
docker-compose -f compose-file.yml stop
docker-compose -f compose-file.yml down
# down关闭所有服务并把容器也删除,而stop仅仅关闭所有服务
一般操作如下:
# 拉取镜像,重新启动服务
docker login -u "$DOCKER_ACCESS_KEY" -p "$DOCKER_ACCESS_TOKEN"
docker-compose -f compose/docker-compose-dev.yml down
docker rmi -f ginlink/sheep-web:dev
docker-compose -f compose/docker-compose-dev.yml up -d
[1] Get started with Docker Compose.https://docs.docker.com/compose/gettingstarted/
31 总结自动化部署的一系列操作
TODO
32 vite2+vue3最佳实践
[1] 2021必知必会的vite+vue3项目最佳实践.https://blog.csdn.net/l1063951462/article/details/114941408
(项目地址:https://github.com/57code/vite2-in-action)
33 mac如何切图-并上传到蓝湖
第一步:下载sketch
https://www.macwk.com/soft/sketch
第二步:按照蓝湖教程继续
https://sos.lanhuapp.com/lan-hu-xiang-xi-jiao-cheng.html#21-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6
[1] mac免费软件下载.https://www.macwk.com/
34 mac抓包
[1] MAC系统利用charles抓取微信小程序和手机APP数据包(http和https数据包).https://www.jb51.net/article/147633.htm
[2] Charles 4.6.3b1 破解版 (http抓包神器) (官方版 + 激活码).https://www.macwk.com/soft/charles
抓http大题步骤:
第一步:设置charles的代理开启8888端口
第二步:让mac和手机处于统一网络
需要一个wifi
第三步:charles会弹出提示,开始记录
抓https的步骤:
TODO
35 nestjs(koa2)文档
nestjs的v8文档:https://github.com/nestcn/docs.nestjs.cn/blob/master/8/about.md
node相关学习文档:https://github.com/nestcn/docs.nestjs.cn
目的:用nestjs搭建一个文件上传的后台服务
nest + mysql + graph
一个示例:
nest mysql 实战.https://blog.csdn.net/u014196765/article/details/107184616/
项目地址:https://github.com/baiqingchun/nest
36 graphql
视频学习:bilibili
38 如何从头搭建webpack项目
大致步骤:
yarn init=> 安装webpack以及cli=> 配置=> 性能优化
配置
- 创建配置文件
- 配置mode、入口、出口
- 配置html插件(以模板引入),文档地址:https://github.com/jantimon/html-webpack-plugin
- 配置开发环境serve、热更新
- 配置ts支持(ts-loader)
- 配置npm启动、打包脚本
[1] webpack5文档.https://webpack.docschina.org/guides/
39 mac安装mysql(包含客户端和服务器端)
brew install mysql
#进入数据库
mysql -u root -p #默认IP和端口
mysql -h 192.168.218.129 -u root -p -P 3306 #指定IP和端口
#如果要做服务端,则启动数据库
brew services start mysql
错误:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
描述:输入mysql -u root -p之后,出现以上错误
原因:mysql运行在docker之中,而以上命令是链接本机(127.0.0.1)的mysql
解决方案1:指定地址和端口
mysql -h 192.168.3.72 -u root -p -P 3307
#3307是启动容器暴露给主机的端口,为了与本机3306区分
注意不能只安装客户端mysql, ,不安装服务端mysql也可以服务端mysql也要安装
解决方案2:通过容器ip直接链接(前提是可以ping通容器ip)
首先进入容器
docker exec -it 容器id bash
进入mysql数据库开启远程访问权限
mysql -uroot -p
use mysql;
update user set password_expired="Y" where user="root";
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root';
cmd 远程连接
mysql -h 192.168.218.129 -u root -p -P 3306
[1] Mac终端安装mysql教程.https://blog.csdn.net/m0_46481239/article/details/105590054
[2] 本机连接虚拟机中docker启动的mysql数据库.https://www.cnblogs.com/zwq-/p/11221013.html
错误:npm的mysql包报错-ER_NOT_SUPPORTED_AUTH_MODE
解决方案:
mysql -u root -p
use mysql;
ALTER USER the_user IDENTIFIED WITH mysql_native_password BY 'the_password';
[1] ER_NOT_SUPPORTED_AUTH_MODE #2499.https://github.com/mysqljs/mysql/issues/2499
40 一个prettier的通用配置库
yarn add -D @fantasticit/code-lint
使用
// .prettierrc.js
const config = require('@fantasticit/code-lint/lib/config/prettier')();
module.exports = config
41 ts中的装饰器有什么用?
ts中的装饰器就是一个
函数
,参数中包含修饰对象的所有信息,然后可以对这些信息进行加工。被修饰对象可以是类、属性、方法、参数,针对于不同对象传入的参数也不同。注意:装饰器是
javascript
中的概念。