Git Product home page Git Product logo

blog's Introduction

Hi 👋, I'm 0fengzi0

这是第次访问


my github stats

我的原神

Genshin game card

我的项目

演示地址 仓库 说明
个人博客 G-Blog 一个使用GitHub Pages制作的纯前端博客
VOCALTTS-V家语音合成 vocaltts-html 一个让VOCALOID歌姬说话的工具
PyOnline-Python在线编辑器 一个可以在线运行Python的网站
Html学习项目 My_Html_Study 我的前端学习存档
Python学习项目 My_Python_Study 我的Python学习存档
KDS叫号 KDS 一个用来排队叫号的安卓应用

其他我

blog's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

blog's Issues

查看docker的ip

方法1 进入docker内部查看

sudo docker exec -it 容器 bash
ifconfig

方法2 通过docker命令查看

docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container-ID>
docker inspect <container id>
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id

方法3 ~/.bashrc 中写一个 bash 函数

echo function docker_ip() { sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' $1 } >> ~/.bashrc
source ~/.bashrc

使用

docker_ip <container-ID>

参考文档

如何获取 docker 容器(container)的 ip 地址

从0开始编译安卓内核

先记录下设备以及环境

k v
目标设备 小米8
编译环境 docker
ubuntu 18.04
kernel 小米开源

创建docker

docker run --name kernel -it ubuntu:18.04 bash

修改软件源

echo "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list
dpkg --add-architecture i386
apt-get update

安装一些必要的工具

apt-get install -y bc bison build-essential ccache curl flex g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5-dev libsdl1.2-dev libssl-dev libwxgtk3.0-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev unzip openjdk-8-jdk language-pack-zh-hans python vim

配置代理(如果没有,速度会非常慢)

export http_proxy=http://192.168.123.3:10809
export https_proxy=https://192.168.123.3:10809
git config --global http.proxy http://192.168.123.3:10809
git config --global https.proxy https://192.168.123.3:10809

下载代码

git clone --depth=1 https://github.com/MiCode/Xiaomi_Kernel_OpenSource.git -b dipper-q-oss

下载编译器

因为googlesource 最新master分之已经删除了gcc编译器,所以我们需要切换到其他的分之,或者使用官方推荐的(看小米的教程,卡在这里很久,总是提示找不到gcc)

git clone --depth=1 https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9 -b ndk-release-r21

配置编译器

export ARCH=arm64
export SUBARCH=arm64
export CROSS_COMPILE=$(pwd)/bin/aarch64-linux-android-

CROSS_COMPILE 中的$(pwd)代表的是aarch64-linux-android-4.9目录


以上为准备工作,接下来开始编译

编译只需要两步

1.查找并确定 defconf文件, 这个文件的路径一般在内核源码的arch/arm64/configs目录下, 会有一大堆的 defconf文件, 找到最适配你的机型的 defconf文件, 我这里是 dipper_user_defconfig

make O=out dipper_user_defconfig

2.进入内核源码的根目录并开始编译,其中-j4代表4个线程

make O=out -j4

最后等待编译完成


编译完成的文件会输出在out目录下,接下来就需要把out/arch/arm64/boot/Image.gz-dtb打包到boot.img中刷入即可

参考资料

wsl2迁移镜像到其他盘

原理部分

  1. 导出镜像到文件
  2. 删除wsl2容器
  3. 将导出的文件重新导入到wsl2中,并且指定目录
  4. (可选)删除导出的文件

powershell脚本

注意! 请确保期望迁移目录的存在

# wsl2_move_image.ps1 
# WSL存储位置一键迁移脚本
# 
# Powershell Script 3.0+ 
# --------------------------------------------------------------------------------------- 
# 脚本使用方式(需使用管理员权限执行): 
# .\wsl2_move_image.ps1  -target "D:\wsl\" -image  "ubuntu"
# --------------------------------------------------------------------------------------- 
# 
# target: 期望迁移的目录 image需要迁移的镜像
param([string]$target="E:\wsl",[string]$image="ubuntu")

mkdir $target\$image\tmp
mkdir $target\$image\data

Write-Host "Stop docker ..."
net stop "com.docker.service"

Write-Host "Stop wsl ..."
wsl --shutdown

Write-Host "Move $image image ..."
wsl --export $image $target\$image\tmp\$image.tar
Write-Host "Delete $image image ..."
wsl --unregister $image
Write-Host "Import $image image ..."
wsl --import $image $target\$image\data\ $target\$image\tmp\$image.tar --version 2
# Remove-Item $target\$image\tmp\$image.tar -recurse

Write-Host "Finish."

参考资料

WSL2 迁移 Docker 镜像存储位置

腾讯云Serveless部署thinkphp6采坑记录

说明

最近为了需(sheng)要(qian)所以选择了腾讯云serveless进行开发,查看文档时发现提供了thinkphp6的迁移指南,发现很简单,于是就更坚定了选择

采坑记录

  1. 首先根据文档创建一个thinkphp6工程

    注意:你本地的PHP版本一定不能高于7.2.2

    composer create-project topthink/think tp
  2. 修改composer.json

    # 原内容
    {
        # ...
        "config": {
            "preferred-install": "dist"
        }
        # ...
    }
    
    # 修改成这样
    {
        # ...
        "config": {
            "preferred-install": "dist",
            "platform": {
                "php": "7.2.2"
            }
        }
        # ...
    }
  3. 删除你的composer.lock 然后重新进行composer install

  4. 因为我需要多应用模式所以还需要安装topthink/think-multi-app

    composer require topthink/think-multi-app
  5. 修改日志写入相关设置

    因为serveless只有 /tmp目录可写,为了防止thinkphp报错,我们把日志写入到/tmp目录下

    // 日志保存目录
    'path'           => app()->getRuntimePath(),
  6. 修改Session相关设置

    同5的原因,session需要写入到数据库中

    因为暂时没有session相关需求,所以这里就没有修改了

  7. 安装腾讯云serveless工具

    npm install -g serverless
  8. 创建 serverless.yml 文件,在其中进行如下配置

    # serverless.yml
    stage: dev
    component: thinkphp
    name: thinkphpDemo
    
    inputs:
        # 函数地区设置
        region: ap-guangzhou
        # 云函数名称
        functionName: thinkphpDemo
        # 运行环境
        runtime: Php7
        # api网关服务名称
        serviceName: thinkphpDemo
        src:
            # 本地需要打包的文件目录
            src: ./
            # 被排除的文件或目录
            exclude:
                - .env
                - .git
                - .idea
                - .example.env
        functionConf:
            # 超时时间,单位秒
            timeout: 10
            # 是否固定出口IP
            eip: true
            # 内存大小,单位MB
            memorySize: 64
        apigatewayConf:
            #  允许跨域
            enableCORS: true
            # 自定义域名绑定
            customDomains:
                -domain: abc.com
                # 如要设置自定义路径映射,请设置为 false
                isDefaultMapping: false
                # 自定义路径映射的路径。使用自定义映射时,可一次仅映射一个 path 到一个环境,也可映射多个 path 到多个环境。并且一旦使用自定义映射,原本的默认映射规则不再生效,只有自定义映射路径生效。
                pathMappingSet:
                    -   path: /
                        environment: release
                # 绑定自定义域名的协议类型,默认与服务的前端协议一致。
                protocols:
                    - http # 支持http协议
                    - https # 支持https协议
            protocols:
                - http
                - https
  9. 部署到腾讯云serveless

    注意:在部署前,你需要先清理本地运行的配置缓存,执行 php think clear 即可。

    如您的账号未 或 腾讯云,您可以直接通过 微信 扫描命令行中的二维码进行授权登陆和注册。

    通过 sls 命令进行部署,并可以添加 --debug 参数查看部署过程中的信息

    serverless deploy --debug
  10. 登录到serveless修改入口文件

    修改前的getAppName

    function getAppName($path)
    {
        $strpos = strpos($path, '/');
        if($strpos || $strpos == 0) {
            $appname = substr($path, $strpos + 1, strlen($path));
            // check if the folder exists
            $appPath = __DIR__ . "/app/" . $appname;
            if(is_dir($appPath)) {
                return $appname;
            }
        }
        return '';
    }

    修改后的getAppName

    function getAppName($path)
    {
        if (strlen($path) == 1) {
            return "";
        }
        if (substr_count($path, "/") == 1) {
            $appName = substr($path, 1, strlen($path));
        } else {
            $appName = substr($path, 1, strpos($path, '/', 1) - 1);
        }
        // check if the folder exists
        $appPath = __DIR__ . "/app/" . $appName;
        if (is_dir($appPath)) {
            return $appName;
        }
        return "";
    }

    之所以修改时因为多应用模式下无法获取到appName无论你的$path是什么他的代码都会返回"",然后执行下方代码,最后你的appName就变成了index

    附完整的修改前代码和修改后代码,同时为了防止本地直接修改此文件导致部署失败(找不到入口文件)所以文件名称做了修改

    // 修改前 文件名sl_handler.php 执行方法 sl_handler.handler
    <?php
    
    define('TEXT_REG', '#\.html.*|\.js.*|\.css.*|\.html.*#');
    define('BINARY_REG', '#\.ttf.*|\.woff.*|\.gif.*|\.jpg.*|\.png.*|\.jepg.*|\.swf.*|\.bmp.*|\.ico.*#');
    
    /**
     * handler static files
     */
    function handlerStatic($path)
    {
        $filename = __DIR__ . "/public/" . $path;
        $handle   = fopen($filename, "r");
        $contents = fread($handle, filesize($filename));
        fclose($handle);
    
        $base64Encode = false;
        $headers = [
            'Content-Type'  => '',
            'Cache-Control' => "max-age=8640000",
            'Accept-Ranges' => 'bytes',
        ];
        $body = $contents;
        if (preg_match(BINARY_REG, $path)) {
            $base64Encode = true;
            $headers = [
                'Content-Type'  => '',
                'Cache-Control' => "max-age=86400",
            ];
            $body = base64_encode($contents);
        }
        return [
            "isBase64Encoded" => $base64Encode,
            "statusCode" => 200,
            "headers" => $headers,
            "body" => $body,
        ];
    }
    
    function handler($event, $context)
    {
        require __DIR__ . '/vendor/autoload.php';
    
        // init path
        $path = '/' == $event->path ? '' : ltrim($event->path, '/');
    
        $filename = __DIR__ . "/public/" . $path;
        if (file_exists($filename) && (preg_match(TEXT_REG, $path) || preg_match(BINARY_REG, $path))) {
            return handlerStatic($path);
        }
    
        $headers = $event->headers ?? [];
        $headers = json_decode(json_encode($headers), true);
    
        $_GET = $event->queryString ?? [];
        $_GET = json_decode(json_encode($_GET), true);
    
        $_SERVER['REQUEST_METHOD'] = $event->httpMethod;
    
    
        $_POST = [];
    
        if(!empty($event->body)) {
          $jsonobj = json_decode($event->body, true);
          if (is_array($jsonobj) && !empty($jsonobj)) {
            foreach ($jsonobj as $k => $v) {
              $_POST[$k] = $v;
            }
          } else {
            $_POSTbody = explode("&", $event->body);
            foreach ($_POSTbody as $postvalues) {
              $tmp=explode("=", $postvalues);
              $_POST[$tmp[0]] = $tmp[1];
            }
          }
        }
    
        $app = new \think\App();
        // set runtime path to in /tmp, because only /tmp is writable for cloud
        $app->setRuntimePath('/tmp/runtime' . DIRECTORY_SEPARATOR);
    
        $http = $app->http;
    
        // make request
        $request = $app->make('request', [], true);
        $request->setPathinfo($path);
        $request->setMethod($event->httpMethod);
        $request->withHeader($headers);
    
        // Check if it is running in multi-app
        $isMultiApp = isMultiApp($app);
        if($isMultiApp) {
            $appName = getAppName("/".$path);
            if($appName == '') {
                // if app name not included in the request path,
                // find the default one defined in config/app.php
                include_once $app->getThinkPath() . 'helper.php'; // include helper for env()
                $appConfig = require __DIR__ . '/config/app.php';
                $appName = isset($appConfig['default_app']) ? $appConfig['default_app'] : 'index';
            } else {
                $request->setPathinfo(substr($path, strlen($appName)));
            }
            $response = $http->name($appName)->run($request);
        } else {
            $response = $http->run($request);
        }
    
        // get response
        $http->end($response);
    
        $body = $response->getContent();
        $contentType = $response->getHeader('Content-Type');
    
        return [
            'isBase64Encoded' => false,
            'statusCode' => $response->getCode(),
            'headers' => [
                'Content-Type' => $contentType
            ],
            'body' => $body
        ];
    }
    
    function isMultiApp() : bool
    {
      return is_dir(__DIR__ . "/app/" . 'controller') ? false : true;
    }
    
    function getAppName($path)
    {
        $strpos = strpos($path, '/');
        if($strpos || $strpos == 0) {
            $appname = substr($path, $strpos + 1, strlen($path));
            // check if the folder exists
            $appPath = __DIR__ . "/app/" . $appname;
            if(is_dir($appPath)) {
                return $appname;
            }
        }
        return '';
    }
    // 修改后 文件名 index.php 执行方法 index.main
    <?php
    
        define('TEXT_REG', '#\.html.*|\.js.*|\.css.*|\.html.*#');
        define('BINARY_REG', '#\.ttf.*|\.woff.*|\.gif.*|\.jpg.*|\.png.*|\.jepg.*|\.swf.*|\.bmp.*|\.ico.*#');
    
        /**
         * handler static files
         */
        function handlerStatic($path)
        {
            $filename = __DIR__ . "/public/" . $path;
            $handle = fopen($filename, "r");
            $contents = fread($handle, filesize($filename));
            fclose($handle);
    
            $base64Encode = FALSE;
            $headers = [
                    'Content-Type'  => '',
                    'Cache-Control' => "max-age=8640000",
                    'Accept-Ranges' => 'bytes',
            ];
            $body = $contents;
            if (preg_match(BINARY_REG, $path)) {
                $base64Encode = TRUE;
                $headers = [
                        'Content-Type'  => '',
                        'Cache-Control' => "max-age=86400",
                ];
                $body = base64_encode($contents);
            }
            return [
                    "isBase64Encoded" => $base64Encode,
                    "statusCode"      => 200,
                    "headers"         => $headers,
                    "body"            => $body,
            ];
        }
    
        function main($event, $context)
        {
            require __DIR__ . '/vendor/autoload.php';
    
            // init path
            $path = '/' == $event->path ? '' : ltrim($event->path, '/');
    
            $filename = __DIR__ . "/public/" . $path;
            if (file_exists($filename) && (preg_match(TEXT_REG, $path) || preg_match(BINARY_REG, $path))) {
                return handlerStatic($path);
            }
    
            $headers = $event->headers ?? [];
            $headers = json_decode(json_encode($headers), TRUE);
    
            $_GET = $event->queryString ?? [];
            $_GET = json_decode(json_encode($_GET), TRUE);
    
            $_SERVER['REQUEST_METHOD'] = $event->httpMethod;
    
    
            $_POST = [];
    
            if (!empty($event->body)) {
                $jsonobj = json_decode($event->body, TRUE);
                if (is_array($jsonobj) && !empty($jsonobj)) {
                    foreach ($jsonobj as $k => $v) {
                        $_POST[$k] = $v;
                    }
                } else {
                    $_POSTbody = explode("&", $event->body);
                    foreach ($_POSTbody as $postvalues) {
                        $tmp = explode("=", $postvalues);
                        $_POST[$tmp[0]] = $tmp[1];
                    }
                }
            }
    
            $app = new \think\App();
            // set runtime path to in /tmp, because only /tmp is writable for cloud
            $app->setRuntimePath('/tmp/runtime' . DIRECTORY_SEPARATOR);
    
            $http = $app->http;
    
            // make request
            $request = $app->make('request', [], TRUE);
            $request->setPathinfo($path);
            $request->setMethod($event->httpMethod);
            $request->withHeader($headers);
    
            // Check if it is running in multi-app
            $isMultiApp = isMultiApp($app);
            if ($isMultiApp) {
                $appName = getAppName("/" . $path);
                if ($appName == '') {
                    // if app name not included in the request path,
                    // find the default one defined in config/app.php
                    include_once $app->getThinkPath() . 'helper.php'; // include helper for env()
                    $appConfig = require __DIR__ . '/config/app.php';
                    $appName = isset($appConfig['default_app']) ? $appConfig['default_app'] : 'index';
                } else {
                    $request->setPathinfo(substr($path, strlen($appName)));
                }
                $response = $http->name($appName)->run($request);
            } else {
                $response = $http->run($request);
            }
    
            // get response
            $http->end($response);
    
            $body = $response->getContent();
            $contentType = $response->getHeader('Content-Type');
    
            return [
                    'isBase64Encoded' => FALSE,
                    'statusCode'      => $response->getCode(),
                    'headers'         => [
                            'Content-Type' => $contentType,
                    ],
                    'body'            => $body,
            ];
        }
    
        function isMultiApp(): bool
        {
            return is_dir(__DIR__ . "/app/" . 'controller') ? FALSE : TRUE;
        }
    
        function getAppName($path)
        {
            if (strlen($path) == 1) {
                return "";
            }
            if (substr_count($path, "/") == 1) {
                $appName = substr($path, 1, strlen($path));
            } else {
                $appName = substr($path, 1, strpos($path, '/', 1) - 1);
            }
            // check if the folder exists
            $appPath = __DIR__ . "/app/" . $appName;
            if (is_dir($appPath)) {
                return $appName;
            }
            return "";
        }

最后

牢记serveless可写目录只有 /tmp,所有需要写入的文件只能放在这里,不然代码会报错

记录下自己踩过的坑,以防忘记

ubuntu下nodejs升级

ubuntu下升级nodejs版本

1.更新apt

sudo apt-get update
sudo apt-get upgrade

2.安装nodejs ,在这里安装npm可能会有问题, 腾讯云安装npm失败 #8

sudo apt-get install nodejs
sudo apt-get install npm

3.升级

sudo npm cache clean -f
sudo npm install -g n
sudo n stable

4.查看版本(可能需要重新连接)

node -v
npm -v

Termux安装vscode

# 更新应用
apt update && apt upgrade

# 安装proot环境
apt install proot-distro

# 安装 ubuntu镜像
proot-distro install ubuntu

# 切换到ubuntu
proot-distro login ubuntu

# 更新
apt update && apt upgrade

# 安装依赖
apt install build-essential python git nodejs yarn

# 安装code service
yarn global add code-server

#启动
code-server

可能用到的命令

# termux 换源
termux-change-repo

Ubuntu换源
#15 ubuntu 换源

Docker常用命令记录

安装docker

下载地址,win10需要开启wsl2,自行安装即可

创建

以nginx为例,在控制台输入docker pull nginx:latest等待创建完成即可
如果需要创建其他的镜像,可从Docker Hub中查找

启动容器

控制台输入docker run --name nginx-test -p 43210:80 -d nginx即可
其中参数

--name 给容器起个名字 目前是nginx-test
-p 映射端口 把主机的43210绑定到容器的80端口上,可理解为路由器上的端口映射
-d 需要启动的容器名,也就是上方安装的名字

更多参数可在docker help查看
容器启动后访问http://127.0.0.1:43210即可打开nginx的初始页面

停止一个容器

docker stopdocker kill
二者区别stop是类似虚拟机的正常关机,kill是强制停止

重新启动一个已经停止的容器

docker restart nginx-test
其中nginx-test是创建时的名字
再次启动时无需绑定端口

查看当前运行的容器

docker ps

删除none镜像

docker rmi $(docker images -f "dangling=true" -q)

启动一个带有交互的容器

docker run -i -t ubuntu /bin/bash
其中

-i: 交互式操作。
-t: 终端。
ubuntu: ubuntu 镜像。
/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

docker run 参数

runoob@runoob:~$ docker run -it nginx:latest /bin/bash  
root@b8573233d675:/#   



Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]    
02.  
03.  -d, --detach=false         指定容器运行于前台还是后台,默认为false     
04.  -i, --interactive=false   打开STDIN,用于控制台交互    
05.  -t, --tty=false            分配tty设备,该可以支持终端登录,默认为false    
06.  -u, --user=""              指定容器的用户    
07.  -a, --attach=[]            登录容器(必须是以docker run -d启动的容器)  
08.  -w, --workdir=""           指定容器的工作目录   
09.  -c, --cpu-shares=0        设置容器CPU权重,在CPU共享场景使用    
10.  -e, --env=[]               指定环境变量,容器中可以使用该环境变量    
11.  -m, --memory=""            指定容器的内存上限    
12.  -P, --publish-all=false    指定容器暴露的端口    
13.  -p, --publish=[]           指定容器暴露的端口   
14.  -h, --hostname=""          指定容器的主机名    
15.  -v, --volume=[]            给容器挂载存储卷,挂载到容器的某个目录    
16.  --volumes-from=[]          给容器挂载其他容器上的卷,挂载到容器的某个目录  
17.  --cap-add=[]               添加权限,权限清单详见:http://linux.die.net/man/7/capabilities    
18.  --cap-drop=[]              删除权限,权限清单详见:http://linux.die.net/man/7/capabilities    
19.  --cidfile=""               运行容器后,在指定文件中写入容器PID值,一种典型的监控系统用法    
20.  --cpuset=""                设置容器可以使用哪些CPU,此参数可以用来容器独占CPU    
21.  --device=[]                添加主机设备给容器,相当于设备直通    
22.  --dns=[]                   指定容器的dns服务器    
23.  --dns-search=[]            指定容器的dns搜索域名,写入到容器的/etc/resolv.conf文件    
24.  --entrypoint=""            覆盖image的入口点    
25.  --env-file=[]              指定环境变量文件,文件格式为每行一个环境变量    
26.  --expose=[]                指定容器暴露的端口,即修改镜像的暴露端口    
27.  --link=[]                  指定容器间的关联,使用其他容器的IP、env等信息    
28.  --lxc-conf=[]              指定容器的配置文件,只有在指定--exec-driver=lxc时使用    
29.  --name=""                  指定容器名字,后续可以通过名字进行容器管理,links特性需要使用名字    
30.  --net="bridge"             容器网络设置:  
31.                                bridge 使用docker daemon指定的网桥       
32.                                host    //容器使用主机的网络    
33.                                container:NAME_or_ID  >//使用其他容器的网路,共享IP和PORT等网络资源    
34.                                none 容器使用自己的网络(类似--net=bridge),但是不进行配置   
35.  --privileged=false         指定容器是否为特权容器,特权容器拥有所有的capabilities    
36.  --restart="no"             指定容器停止后的重启策略:  
37.                                no:容器退出时不重启    
38.                                on-failure:容器故障退出(返回值非零)时重启   
39.                                always:容器退出时总是重启    
40.  --rm=false                 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)    
41.  --sig-proxy=true           设置由代理接受并处理信号,但是SIGCHLD、SIGSTOP和SIGKILL不能被代理    

常用代理设置

git

设置代理

# http代理
git config --global http.proxy http://127.0.0.1:10809
git config --global https.proxy http://127.0.0.1:10809

# socks5代理
git config --global http.proxy "socks5://127.0.0.1:10808"
git config --global https.proxy "socks5://127.0.0.1:10808"

取消代理

git config --global --unset http.proxy
git config --global --unset https.proxy

bash

设置代理

# http代理
export http_proxy="http://127.0.0.1:10809"
export https_proxy="http://127.0.0.1:10809"

# socks5代理
export http_proxy="socks5://127.0.0.1:10808"
export https_proxy="socks5://127.0.0.1:10808"

取消代理

unset http_proxy
unset https_proxy

powershell

# http代理
$env:HTTP_PROXY="http://127.0.0.1:10809"
$env:HTTPS_PROXY="http://127.0.0.1:10809"

取消代理

$env:HTTP_PROXY=""
$env:HTTPS_PROXY=""

CMD

设置代理

# http代理
set http_proxy=http://127.0.0.1:10809
set https_proxy=http://127.0.0.1:10809
# socks5代理
set http_proxy=socks5://127.0.0.1:10808
set https_proxy=socks5://127.0.0.1:10808

取消代理

set http_proxy=
set https_proxy=

npm

设置代理

# http代理
npm config set proxy http://127.0.0.1:10809
npm config set https-proxy http://127.0.0.1:10809

取消代理

npm config delete proxy
npm config delete https-proxy

yarn

设置代理

yarn config set proxy http://127.0.0.1:10809
yarn config set https-proxy http://127.0.0.1:10809

取消代理

yarn config delete proxy
yarn config delete https-proxy

Ubuntu用户管理(创建用户、切换用户、修改密码等)

修改密码

sudo passwd 用户名

创建用户

adduser 用户名

添加root权限,修改文件/etc/sudoers,如果没有则检查是否有sudo,没有则apt install sudo

root ALL=(ALL) ALL
用户名 ALL=(ALL) ALL

切换用户

su 用户名

终端提示符$表示普通用户,#表示超级用户,即root用户

Wsl2和加速器冲突的问题

  1. win10 pro 20h2 安装 docker 开启wsl2 后续安装了腾讯 WeGame 和 cf 再次开机时 docker 报错 , 大致原因是 wsl2 的问题
    打开 基于 wsl2 的 ubuntu 后出现 【参考的对象类型不支持尝试的操作】 查找得知是代理相关原因

解决办法

  1. 临时解决
    管理员模式打开cmd输入
netsh winsock reset

2.永久解决
下载工具

管理员模式运行cmd

NoLsp.exe C:\Windows\System32\wsl.exe

解决问题


参考资料

1.知乎-关于使用WSL2出现“参考的对象类型不支持尝试的操作”的解决方法
2.GitHub - Wsl

MyBatis-Plus代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
上代码

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {

    // 数据库驱动名称
    private static final String dataSourceDriverName = "com.mysql.cj.jdbc.Driver";
    // 应用包名
    private static final String packageName = "com.ixf";
    // 数据库名
    private static final String dataSourceName = "testapi";
    // 数据用户名
    private static final String dataSourceUserName = "testapi";
    // 数据库密码
    private static final String dataSourcePassWord = "testapi";
    // 实体类的父类
    private static final String entityFatherClass = "";
    // 控制器的父类
    private static final String controllerFatherClass = "";


    /**
     * <p>
     * 读取控制台内容
     * </p>
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotBlank(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("jobob");
        gc.setOpen(false);
        // gc.setSwagger2(true); 实体属性 Swagger2 注解
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/" + dataSourceName + "?useUnicode=true&useSSL=false&characterEncoding=utf8&&serverTimezone=UTC");
        // dsc.setSchemaName("public");
        dsc.setDriverName(dataSourceDriverName);
        dsc.setUsername(dataSourceUserName);
        dsc.setPassword(dataSourcePassWord);
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent(packageName);
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 如果模板引擎是 velocity
        // String templatePath = "/templates/mapper.xml.vm";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
                        + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        /*
        cfg.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建
                checkDir("调用默认方法创建的目录,自定义目录用");
                if (fileType == FileType.MAPPER) {
                    // 已经生成 mapper 文件判断存在,不想重新生成返回 false
                    return !new File(filePath).exists();
                }
                // 允许生成模板文件
                return true;
            }
        });
        */
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        if (!"".equals(entityFatherClass)) strategy.setSuperEntityClass(entityFatherClass);
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        // 公共父类
        if (!"".equals(controllerFatherClass)) strategy.setSuperControllerClass(controllerFatherClass);
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }

}

一键脚本收集

宝塔一键(ubuntu)

wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh && sudo bash install.sh

docker安装

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

vps一键检测

curl -Lso- bench.sh | bash

docker内控制宿主机docker

docker中执行宿主机的docker操作,我们管它叫docker in docker。
至于为什么要在docker中操作宿主机的docker,优点不言而喻,你既可以将你的具体需求容器化部署,又不用直接在宿主机上安装(假设我们没有办法在docker中操作宿主机的docker,那么我们只能将这样的软件程序直接安装到宿主机上,这样显然是不利于管理和维护的)。

实现这种需求,其实非常简单,你只需要将docker宿主机的docker文件和docker.sock文件挂载到容器中即可

比如创建容器时

-v /var/run/docker.sock:/var/run/docker.sock 
-v /usr/bin/docker:/usr/bin/docker

友链

这是友链页面,但是现在还没有信息

Vant使用REM,配置后控制台报错

错误信息

  Replace Autoprefixer browsers option to Browserslist config.
  Use browserslist key in package.json or .browserslistrc file.

  Using browsers option can cause errors. Browserslist config 
  can be used for Babel, Autoprefixer, postcss-normalize and other tools.

  If you really need to use option, rename it to overrideBrowserslist.

  Learn more at:
  https://github.com/browserslist/browserslist#readme
  https://twitter.com/browserslist

出现的原因

autoprefixer版本比较高,与原文档的版本不符,新版本写法发生改变

解决方法

postcss.config.js文件修改

//原配置
module.exports = {
    plugins: {
        autoprefixer: {
            browsers: ['Android >= 4.0', 'iOS >= 8'],
        },
        'postcss-pxtorem': {
            rootValue: 37.5,
            propList: ['*'],
        },
    },
};

// 修改后配置
module.exports = {
    plugins: {
        'autoprefixer': {
            overrideBrowserslist: [
                'Android 4.1',
                'iOS 7.1',
                'Chrome > 31',
                'ff > 31',
                'ie >= 8'
            ]
        },
        'postcss-pxtorem': {
            rootValue: 37.5,
            propList: ['*']
        }
    }
};

参考教程

vue项目配置 autoprefixer 报出警告问题

linux openssl 升级

原因说明

近日腾讯云提示 系统组件漏洞

2020年04月21日OpenSSL 官方发布了 TLS 1.3 组件拒绝服务漏洞的风险通告,当服务端或客户端程序收到一个无效或无法识别的签名算法时可能会引发崩溃或拒绝服务漏洞,黑客可利用该漏洞攻击服务器,导致无法正常提供服务。

修复方法为

升级到 1.1.1g 版本,下载地址为:https://www.openssl.org/source/
需确认机器已安装的软件包中不存在低版本openssl组件,例如可通过执行rpm -qa | grep openssl查看

升级操作

本次升级到的版本为1.1.1h

  1. 下载openssl
wget https://www.openssl.org/source/openssl-1.1.1h.tar.gz
  1. 解压
tar zxvf openssl-1.1.1h.tar.gz

3.编译并安装

cd openssl-1.1.1h.tar.gz
./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl
make
make install

4.备份老的

mv /usr/bin/openssl /usr/bin/openssl.bak
mv /usr/include/openssl /usr/include/openssl.bak

5.更新

ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/openssl/include/openssl /usr/include/openssl
echo "/usr/local/openssl/lib" >> /etc/ld.so.conf

6.重新加载配置以生效

/sbin/ldconfig

7.查看openssl版本确认安装完成

openssl version

8.若出现undefined symbol: EVP_mdc2, version OPENSSL_1_1_0,有可能是你的libcrypto.so.1.1有些老,可使用stat命令查看修改时间

stat /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1

>
Access: 2020-11-23 18:42:31.627823944 +0800 (访问时间)
Modify: 2020-11-23 18:42:30.855818069 +0800 (创建时间)
Change: 2020-11-23 18:42:30.855818069 +0800 (修改时间)

此时需要将我们新编译成功文件替换掉老的

mv /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1.bak
ln -s /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1

此时再次执行第七步即可查看到openssl版本


参考文章

TLS配置

server {
  listen  443 ssl http2; # 如果你木有添加 HTTP2 模块,请删除 http2
  server_name           test.com #  域名
  ssl_certificate       /home/ssl/b.crt; # 证书
  ssl_certificate_key   /home/ssl/a.key; # 密钥
  ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers           HIGH:!aNULL:!MD5;
        location / {
                proxy_pass http://localhost:8080; # 端口
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}

node-sass安装失败的解决方法

只需要设定node-sass的安装源即可
npm

npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass

yarn

yarn config set sass-binary-site http://npm.taobao.org/mirrors/node-sass

对程序设计的一些想法

本文记录的一些想法是在thinkphp6的基础上提出的。

  • 项目使用多应用模式进行开发,创建common目录存放一些不可访问的类库,开启控制器后缀controller防止类名重复,开发时不方便区分。

  • common创建base目录存放基础类,比如BaseController BaseModel BaseMiddleware BaseException

  • 使用中间件middleware功能进行控制器操作

  • 使用doctrine/annotations插件进行注解开发

  • 使用验证器validate进行请求数据的校验,并结合中间件、注解插件、验证场景进行控制器中间件数据验证

  • 所有数据必须通过控制器进行对外输出,成功输出信息,失败输出信息

  • app应用目录下创建Service目录,并在这里完成操作,除了异常问题,所以数据处理结束后返回,交由controller层进行判断处理

  • 权限验证在中间件进行完成,部分操作需要记录日志,以备后期校对

  • 统一的接口输出

    成功返回的输出

    {
        "code":200,
        "message":"成功",
        "data":{},
        "session_id":"123456"
    }

    失败返回的数据

    {
        "code":3001,
        "message":"你还没有登录,请登录后再试",
        "data":{},
        "session_id":"123456"
    }
  • 异常代码设计

    所有的异常代码可设计为4位数字

分类 区间 分类描述
1*** 1000-1999 服务器已经收到请求,需要继续请求信息
2** 200 服务器接收数据,并且正常处理
3*** 3000-3999 重定向类的,需要前端继续处理
4*** 4000-4999 客户端方面错误,需要重新提交数据
5*** 5000-5999 服务器方面错误,客户端无法处理,应当记录日志并通知管理员进行处理
  • controller层进行数据校验,service处理业务逻辑,碰到异常直接抛出,只会给controller层返回成功的数据,dao层负责数据库相关处理 参考资料:如何设计service层

windows-ubuntu双系统卸载后清除无用的启动项

  1. 右键开始菜单,运行,diskpart (不是cmd,但是可通过cmd中快速打开diskpart窗口)
  2. list disk 列出所有磁盘信息
  3. select disk 0 要选中系统安装盘 (硬盘=磁盘,磁盘中有多个分区,这里列出的是磁盘)
  4. list partition 列出磁盘中的分区信息。
  5. 其中类型为系统的分区就是EFI分区一般大小再一二百MB,select partition 2选中EFI分区。(一般类型显示为系统)
  6. assign letter=p 给EFI分区分配盘符,这样就可以在资源管理器中看到EFI分区了,但是这时候我们是无法进入该分区的,因为权限不够,我们需要使用管理员权限进入该分区。
  7. 可以用管理员权限随便打开一个软件,比如winrar,7z。然后通过该软件就可以进入该分区了。在EFI文件夹中会有一个ubuntu文件夹,或者grub文件夹,我们将其右键删除即可。
  8. 然后我们回到命令行输入remove letter=p删除EFI分区的盘符。

整个操作流程
找到安装的磁盘->找到分区->给分区分配盘符(正常情况下,此分区无盘符,且不可分配)->使用第三方管理器,以管理员方式运行进入此分区,删除启动项->移除已分配的盘符,系统恢复原状

前端解析excel文件

首先安装xlsx依赖

yarn add xlsx

vue文件中引入xlsx依赖

import XLSX from "xlsx";

通过某种方式获得excel文件(以浏览器上传为例子)

vue

<input id="chooseFile" ref="inputFile"
               style="display: none"
               type="file"
               @change="chooseFile"/>	

js

chooseFile(e) {
    // 上传文件可能是多个,获取上传文件数组的第一个文件
    const file = e.target.files[0];

    // 定义需要的文件类型
    const types = ["xls", "xlsx"];
    // 按点分割上传文件的名字
    const arr = file.name.split(".");
    //判断文件是否为excel文件
    if (!types.find(item => item === arr[arr.length - 1])) {
        // 这里可以进行弹窗提醒,告知文件类型错误

        return;
    }

    // 开始解析excel
    const reader = new FileReader();
    reader.onload = e => {
        let data = new Uint8Array(e.target.result);
        let workbook = XLSX.read(data, {type: 'array'});

        // 将excel文件中第一个数据表的数据转为json格式,如果需要从某一个行开始的数据,可以修改sheet_to_json的第二个参数
        let workbookData = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);
        // workbookData 就是excel的数据
        console.log(workbookData)

    };
    reader.readAsArrayBuffer(file);

    // 解决上传同名文件后无法触发@change事件
    this.$refs.inputFile.value = null;

        },

将数据转为excel文件下载下来

// 设置需要保存的数据内容
let tableData = [
    ['名称', '规格', '售价'],
    ['aaa', '个', '13'],
    ['bbb', '个', '13'],
    ['ccc', '个', '13'],
];

// 创建新的workbook
let wb = XLSX.utils.book_new()
// 根据传入的二维数组,生成包含对应内容的worksheet
let ws = XLSX.utils.aoa_to_sheet(tableData);

// 将worksheet添加进workbook,并指定worksheetd的名字
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');

// 下载生成的excel文件
XLSX.writeFile(wb, "下载文件.xlsx");

参考文档

npm,yarn查看和换源

npm, yarn查看源和换源:

# 查看npm当前镜像源
npm config get registry  

# 设置npm镜像源为淘宝镜像
npm config set registry https://registry.npmmirror.com/

# 查看yarn当前镜像源
yarn config get registry 

# 设置yarn镜像源为淘宝镜像
yarn config set registry https://registry.npmmirror.com/

镜像源地址部分如下:

# npm
https://registry.npmjs.org/

# cnpm
https://r.cnpmjs.org/

# taobao
https://registry.npmmirror.com/

# nj
https://registry.nodejitsu.com/

# rednpm
https://registry.mirror.cqupt.edu.cn/

# npmMirror
https://skimdb.npmjs.com/registry/

# deunpm
http://registry.enpmjs.org/

Nginx跨域配置

    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
    
    if ($request_method = 'OPTIONS') {
      return 204;
    }

使用jdk创建安卓证书

1.安装jdk
2.cmd中执行

keytool -genkey -alias ixf_kds -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore

其中ixf_kds 是证书别名, test.keystore是证书文件名

无编辑器修改debin源

sed -i 's#http://deb.debian.org#https://mirrors.cloud.tencent.com#g' /etc/apt/sources.list

同类型

无编辑器修改ubuntu源 #15

Docker 镜像加速

Linux

创建或修改 /etc/docker/daemon.json

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
     "registry-mirrors": [
          "https://reg-mirror.qiniu.com",
          "https://mirror.ccs.tencentyun.com",
          "http://f1361db2.m.daocloud.io"
     ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

Windows

在桌面右下角状态栏中右键 docker 图标,修改在 Docker Daemon 标签页中的 json

{
     "registry-mirrors": [
          "https://reg-mirror.qiniu.com",
          "https://mirror.ccs.tencentyun.com",
          "http://f1361db2.m.daocloud.io"
     ]
}

目前已知的镜像站

镜像加速器 镜像加速器地址 专属加速器 其它加速
Docker **官方镜像 https://registry.docker-cn.com Docker Hub已关闭
DaoCloud 镜像站 http://f1361db2.m.daocloud.io 可登录,系统分配 Docker Hub
Azure **镜像 https://dockerhub.azk8s.cn Docker Hub、GCR、Quay
科大镜像站 https://docker.mirrors.ustc.edu.cn Docker Hub、GCRQuay(已关闭)
阿里云 https://<your_code>.mirror.aliyuncs.com 需登录,系统分配 Docker Hub
七牛云 https://reg-mirror.qiniu.com Docker Hub、GCR、Quay
网易云 https://hub-mirror.c.163.com Docker Hub
腾讯云 https://mirror.ccs.tencentyun.com Docker Hub
Docker 镜像代理 https://dockerproxy.com/ Docker Hub、GCR、K8S、GHCR

参考内容

加速github

1. 使用github镜像站加速

git config --global url."https://hub.fastgit.xyz/".insteadOf "https://github.com/"
git config --global protocol.https.allow always

2. 使用cloudflare works自定搭建代理

'use strict'
 
/**
 * static files (404.html, sw.js, conf.js)
 */
const ASSET_URL = 'https://hunshcn.github.io/gh-proxy'
// 前缀,如果自定义路由为example.com/gh/*,将PREFIX改为 '/gh/',注意,少一个杠都会错!
const PREFIX = '/'
// git使用cnpmjs镜像、分支文件使用jsDelivr镜像的开关,0为关闭,默认开启
const Config = {
    jsdelivr: 1,
    cnpmjs: 1
}
 
/** @type {RequestInit} */
const PREFLIGHT_INIT = {
    status: 204,
    headers: new Headers({
        'access-control-allow-origin': '*',
        'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
        'access-control-max-age': '1728000',
    }),
}
 
/**
 * @param {any} body
 * @param {number} status
 * @param {Object<string, string>} headers
 */
function makeRes(body, status = 200, headers = {}) {
    headers['access-control-allow-origin'] = '*'
    return new Response(body, {status, headers})
}
 
 
/**
 * @param {string} urlStr
 */
function newUrl(urlStr) {
    try {
        return new URL(urlStr)
    } catch (err) {
        return null
    }
}
 
 
addEventListener('fetch', e => {
    const ret = fetchHandler(e)
        .catch(err => makeRes('cfworker error:\n' + err.stack, 502))
    e.respondWith(ret)
})
 
 
/**
 * @param {FetchEvent} e
 */
async function fetchHandler(e) {
    const req = e.request
    const urlStr = req.url
    const urlObj = new URL(urlStr)
    let path = urlObj.searchParams.get('q')
    if (path) {
        return Response.redirect('https://' + urlObj.host + PREFIX + path, 301)
    }
    // cfworker 会把路径中的 `//` 合并成 `/`
    path = urlObj.href.substr(urlObj.origin.length + PREFIX.length).replace(/^https?:\/+/, 'https://')
    const exp1 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$/i
    const exp2 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:blob)\/.*$/i
    const exp3 = /^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:info|git-).*$/i
    const exp4 = /^(?:https?:\/\/)?raw\.githubusercontent\.com\/.+?\/.+?\/.+?\/.+$/i
    if (path.search(exp1) === 0 || !Config.cnpmjs && (path.search(exp3) === 0 || path.search(exp4) === 0)) {
        return httpHandler(req, path)
    } else if (path.search(exp2) === 0) {
        if (Config.jsdelivr){
            const newUrl = path.replace('/blob/', '@').replace(/^(?:https?:\/\/)?github\.com/, 'https://cdn.jsdelivr.net/gh')
            return Response.redirect(newUrl, 302)
        }else{
            path = path.replace('/blob/', '/raw/')
            return httpHandler(req, path)
        }
    } else if (path.search(exp3) === 0) {
        const newUrl = path.replace(/^(?:https?:\/\/)?github\.com/, 'https://github.com.cnpmjs.org')
        return Response.redirect(newUrl, 302)
    } else if (path.search(exp4) === 0) {
        const newUrl = path.replace(/(?<=com\/.+?\/.+?)\/(.+?\/)/, '@$1').replace(/^(?:https?:\/\/)?raw\.githubusercontent\.com/, 'https://cdn.jsdelivr.net/gh')
        return Response.redirect(newUrl, 302)
    } else {
        return fetch(ASSET_URL + path)
    }
}
 
 
/**
 * @param {Request} req
 * @param {string} pathname
 */
function httpHandler(req, pathname) {
    const reqHdrRaw = req.headers
 
    // preflight
    if (req.method === 'OPTIONS' &&
        reqHdrRaw.has('access-control-request-headers')
    ) {
        return new Response(null, PREFLIGHT_INIT)
    }
 
    let rawLen = ''
 
    const reqHdrNew = new Headers(reqHdrRaw)
 
    let urlStr = pathname
    if (urlStr.startsWith('github')) {
        urlStr = 'https://' + urlStr
    }
    const urlObj = newUrl(urlStr)
 
    /** @type {RequestInit} */
    const reqInit = {
        method: req.method,
        headers: reqHdrNew,
        redirect: 'follow',
        body: req.body
    }
    return proxy(urlObj, reqInit, rawLen, 0)
}
 
 
/**
 *
 * @param {URL} urlObj
 * @param {RequestInit} reqInit
 */
async function proxy(urlObj, reqInit, rawLen) {
    const res = await fetch(urlObj.href, reqInit)
    const resHdrOld = res.headers
    const resHdrNew = new Headers(resHdrOld)
 
    // verify
    if (rawLen) {
        const newLen = resHdrOld.get('content-length') || ''
        const badLen = (rawLen !== newLen)
 
        if (badLen) {
            return makeRes(res.body, 400, {
                '--error': `bad len: ${newLen}, except: ${rawLen}`,
                'access-control-expose-headers': '--error',
            })
        }
    }
    const status = res.status
    resHdrNew.set('access-control-expose-headers', '*')
    resHdrNew.set('access-control-allow-origin', '*')
 
    resHdrNew.delete('content-security-policy')
    resHdrNew.delete('content-security-policy-report-only')
    resHdrNew.delete('clear-site-data')
 
    return new Response(res.body, {
        status,
        headers: resHdrNew,
    })
}

crontab踩坑记录

1.环境变量坑

criontab脚本开头一定要写上环境变量
比如 alpine

PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

2.路径坑

crontab执行的目录是用户目录
比如root用户,执行目录就在/root
需要写shell脚本切换目录后再运行

Jenkins清理构建历史

Jenkins执行脚本
jobName是你要清理的工程名称

def jobName =""
def job = Jenkins.instance.getItem(jobName)
job.getBuilds().each { it.delete() }

GitHub Action 自动编译Vue项目并发布

脚本内容

name: buildAndDeploy

env:
  TZ: Asia/Shanghai

on:
  # 当master分支提交时
  push:
    branches:
      - master

# 开始任务
jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: '12'

      # 安装和构建
      - name: Install and Build
        run: |
          yarn
          yarn run build

      - name: Update dist folder to repository
        env:
          # 仓库用户名
          REPO_USERNAME: ""
          # GitHub Pages仓库名
          DIST_REPO: ""
          # GitHub Token
          GITHUB_TOKEN: ${{ secrets.G_TOKEN }}

        run: |
          git config --global user.email "[email protected]"
          git config --global user.name "GitHub Action"

          cd dist && git init && git add .
          git commit -m "GitHub Actions Auto Builder at $(date +'%Y-%m-%d %H:%M:%S')"
          git push --force --quiet "https://[email protected]/$REPO_USERNAME/$DIST_REPO.git" master:master

使用docker安装Jenkins

sudo docker run --name jenkins -u root -d -p 8080:8080 -p 50000:50000 -v /var/jenkins_home:/var/jenkins_home -v /var/run/docker.sock:/var/run/docker.sock jenkinsci/blueocean 

官方文档

vue编译后页面样式错误

在页面的style标签中加入scoped
例如:

<style scoped>
    .note{
        position: absolute;
        width:400px;
        height:400px;
        margin-left:20%;
    }
</style>

cloudreve docker创建

sudo mkdir -p /dockercnf/cloudreve && sudo touch /dockercnf/cloudreve/conf.ini && sudo touch /dockercnf/cloudreve/cloudreve.db && sudo docker run -d --name cloudreve -e PUID=0 -e PGID=0 -e TZ="Asia/Shanghai" -p 5212:5212 --restart=unless-stopped -v /downloads:/downloads -v /tmp/cloudreve:/cloudreve/uploads -v /dockercnf/cloudreve/conf.ini:/cloudreve/conf.ini -v /dockercnf/cloudreve/cloudreve.db:/cloudreve/cloudreve.db -v /dockercnf/cloudreve/avatar:/cloudreve/avatar xavierniu/cloudreve

git放弃修改,强制覆盖本地代码

在使用Git的过程中,有些时候我们只想要git服务器中的最新版本的项目,对于本地的项目中修改不做任何理会,就需要用到Git pull的强制覆盖,具体代码如下:

git fetch --all
git reset --hard origin/master 
git pull

使用js下载东西

生成Data URLs 并下载文件

Data URL 即前缀为 data: 协议的URL,其允许内容创建者向文档中嵌入小文件。它 由四个部分组成:前缀(data:)、指示数据类型的MIME类型、如果非文本则为可选的base64标记、数据本身。

data:[<mediatype>][;base64],<data>

mediatype 是个 MIME 类型的字符串
例如 "image/jpeg" 表示 JPEG 图像文件。
如果被省略,则默认值为 text/plain;charset=US-ASCII
如果数据是文本类型,你可以直接将文本嵌入 
如果是二进制数据,你可以将数据进行base64编码之后再进行嵌入。
function download (fileName = '测试.txt', type = 'text/json', encoding = 'charset=utf-8', data = '') {
    let dataStr = 'data:' + type + ';' + encoding + ',' + encodeURIComponent(data);
    let downloadAnchorNode = document.createElement('a');
    downloadAnchorNode.setAttribute('href', dataStr);
    downloadAnchorNode.setAttribute('download', fileName);
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
}

例子
f12控制台输入

function download (fileName = '测试.txt', type = 'text/json', encoding = 'charset=utf-8', data = '') {
    let dataStr = 'data:' + type + ';' + encoding + ',' + encodeURIComponent(data);
    let downloadAnchorNode = document.createElement('a');
    downloadAnchorNode.setAttribute('href', dataStr);
    downloadAnchorNode.setAttribute('download', fileName);
    downloadAnchorNode.click();
    downloadAnchorNode.remove();
}

// 下载文本
download("测试.txt",'text/json','charset=utf-8',"你好啊")

// 对象转json
let downloadData = {
        name:"April",
        ager:"18",
        hobby:"学习"
};
download("测试.json",'text/json','charset=utf-8',JSON.stringify(downloadData))

// 下载音频文件
let downloadData = "UklGRhwMAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAZGF0Ya4LAACAgICAgICAgICAgICAgICAgICAgICAgICAf3hxeH+AfXZ1eHx6dnR5fYGFgoOKi42aloubq6GOjI2Op7ythXJ0eYF5aV1AOFFib32HmZSHhpCalIiYi4SRkZaLfnhxaWptb21qaWBea2BRYmZTVmFgWFNXVVVhaGdbYGhZbXh1gXZ1goeIlot1k6yxtKaOkaWhq7KonKCZoaCjoKWuqqmurK6ztrO7tbTAvru/vb68vbW6vLGqsLOfm5yal5KKhoyBeHt2dXBnbmljVlJWUEBBPDw9Mi4zKRwhIBYaGRQcHBURGB0XFxwhGxocJSstMjg6PTc6PUxVV1lWV2JqaXN0coCHhIyPjpOenqWppK6xu72yxMu9us7Pw83Wy9nY29ve6OPr6uvs6ezu6ejk6erm3uPj3dbT1sjBzdDFuMHAt7m1r7W6qaCupJOTkpWPgHqAd3JrbGlnY1peX1hTUk9PTFRKR0RFQkRBRUVEQkdBPjs9Pzo6NT04Njs+PTxAPzo/Ojk6PEA5PUJAQD04PkRCREZLUk1KT1BRUVdXU1VRV1tZV1xgXltcXF9hXl9eY2VmZmlna3J0b3F3eHyBfX+JgIWJiouTlZCTmpybnqSgnqyrqrO3srK2uL2/u7jAwMLFxsfEv8XLzcrIy83JzcrP0s3M0dTP0drY1dPR1dzc19za19XX2dnU1NjU0dXPzdHQy8rMysfGxMLBvLu3ta+sraeioJ2YlI+MioeFfX55cnJsaWVjXVlbVE5RTktHRUVAPDw3NC8uLyknKSIiJiUdHiEeGx4eHRwZHB8cHiAfHh8eHSEhISMoJyMnKisrLCszNy8yOTg9QEJFRUVITVFOTlJVWltaXmNfX2ZqZ21xb3R3eHqAhoeJkZKTlZmhpJ6kqKeur6yxtLW1trW4t6+us7axrbK2tLa6ury7u7u9u7vCwb+/vr7Ev7y9v8G8vby6vru4uLq+tri8ubi5t7W4uLW5uLKxs7G0tLGwt7Wvs7avr7O0tLW4trS4uLO1trW1trm1tLm0r7Kyr66wramsqaKlp52bmpeWl5KQkImEhIB8fXh3eHJrbW5mYGNcWFhUUE1LRENDQUI9ODcxLy8vMCsqLCgoKCgpKScoKCYoKygpKyssLi0sLi0uMDIwMTIuLzQ0Njg4Njc8ODlBQ0A/RUdGSU5RUVFUV1pdXWFjZGdpbG1vcXJ2eXh6fICAgIWIio2OkJGSlJWanJqbnZ2cn6Kkp6enq62srbCysrO1uLy4uL+/vL7CwMHAvb/Cvbq9vLm5uba2t7Sysq+urqyqqaalpqShoJ+enZuamZqXlZWTkpGSkpCNjpCMioqLioiHhoeGhYSGg4GDhoKDg4GBg4GBgoGBgoOChISChISChIWDg4WEgoSEgYODgYGCgYGAgICAgX99f398fX18e3p6e3t7enp7fHx4e3x6e3x7fHx9fX59fn1+fX19fH19fnx9fn19fX18fHx7fHx6fH18fXx8fHx7fH1+fXx+f319fn19fn1+gH9+f4B/fn+AgICAgH+AgICAgIGAgICAgH9+f4B+f35+fn58e3t8e3p5eXh4d3Z1dHRzcXBvb21sbmxqaWhlZmVjYmFfX2BfXV1cXFxaWVlaWVlYV1hYV1hYWVhZWFlaWllbXFpbXV5fX15fYWJhYmNiYWJhYWJjZGVmZ2hqbG1ub3Fxc3V3dnd6e3t8e3x+f3+AgICAgoGBgoKDhISFh4aHiYqKi4uMjYyOj4+QkZKUlZWXmJmbm52enqCioqSlpqeoqaqrrK2ur7CxsrGys7O0tbW2tba3t7i3uLe4t7a3t7i3tre2tba1tLSzsrKysbCvrq2sq6qop6alo6OioJ+dnJqZmJeWlJKSkI+OjoyLioiIh4WEg4GBgH9+fXt6eXh3d3V0c3JxcG9ubWxsamppaWhnZmVlZGRjYmNiYWBhYGBfYF9fXl5fXl1dXVxdXF1dXF1cXF1cXF1dXV5dXV5fXl9eX19gYGFgYWJhYmFiY2NiY2RjZGNkZWRlZGVmZmVmZmVmZ2dmZ2hnaGhnaGloZ2hpaWhpamlqaWpqa2pra2xtbGxtbm1ubm5vcG9wcXBxcnFycnN0c3N0dXV2d3d4eHh5ent6e3x9fn5/f4CAgIGCg4SEhYaGh4iIiYqLi4uMjY2Oj5CQkZGSk5OUlJWWlpeYl5iZmZqbm5ybnJ2cnZ6en56fn6ChoKChoqGio6KjpKOko6SjpKWkpaSkpKSlpKWkpaSlpKSlpKOkpKOko6KioaKhoaCfoJ+enp2dnJybmpmZmJeXlpWUk5STkZGQj4+OjYyLioqJh4eGhYSEgoKBgIB/fn59fHt7enl5eHd3dnZ1dHRzc3JycXBxcG9vbm5tbWxrbGxraWppaWhpaGdnZ2dmZ2ZlZmVmZWRlZGVkY2RjZGNkZGRkZGRkZGRkZGRjZGRkY2RjZGNkZWRlZGVmZWZmZ2ZnZ2doaWhpaWpra2xsbW5tbm9ub29wcXFycnNzdHV1dXZ2d3d4eXl6enp7fHx9fX5+f4CAgIGAgYGCgoOEhISFhoWGhoeIh4iJiImKiYqLiouLjI2MjI2OjY6Pj46PkI+QkZCRkJGQkZGSkZKRkpGSkZGRkZKRkpKRkpGSkZKRkpGSkZKRkpGSkZCRkZCRkI+Qj5CPkI+Pjo+OjY6Njo2MjYyLjIuMi4qLioqJiomJiImIh4iHh4aHhoaFhoWFhIWEg4SDg4KDgoKBgoGAgYCBgICAgICAf4CAf39+f35/fn1+fX59fHx9fH18e3x7fHt6e3p7ent6e3p5enl6enl6eXp5eXl4eXh5eHl4eXh5eHl4eXh5eHh3eHh4d3h4d3h3d3h4d3l4eHd4d3h3eHd4d3h3eHh4eXh5eHl4eHl4eXh5enl6eXp5enl6eXp5ent6ent6e3x7fHx9fH18fX19fn1+fX5/fn9+f4B/gH+Af4CAgICAgIGAgYCBgoGCgYKCgoKDgoOEg4OEg4SFhIWEhYSFhoWGhYaHhoeHhoeGh4iHiIiHiImIiImKiYqJiYqJiouKi4qLiouKi4qLiouKi4qLiouKi4qLi4qLiouKi4qLiomJiomIiYiJiImIh4iIh4iHhoeGhYWGhYaFhIWEg4OEg4KDgoOCgYKBgIGAgICAgH+Af39+f359fn18fX19fHx8e3t6e3p7enl6eXp5enl6enl5eXh5eHh5eHl4eXh5eHl4eHd5eHd3eHl4d3h3eHd4d3h3eHh4d3h4d3h3d3h5eHl4eXh5eHl5eXp5enl6eXp7ent6e3p7e3t7fHt8e3x8fHx9fH1+fX59fn9+f35/gH+AgICAgICAgYGAgYKBgoGCgoKDgoOEg4SEhIWFhIWFhoWGhYaGhoaHhoeGh4aHhoeIh4iHiIeHiIeIh4iHiIeIiIiHiIeIh4iHiIiHiIeIh4iHiIeIh4eIh4eIh4aHh4aHhoeGh4aHhoWGhYaFhoWFhIWEhYSFhIWEhISDhIOEg4OCg4OCg4KDgYKCgYKCgYCBgIGAgYCBgICAgICAgICAf4B/f4B/gH+Af35/fn9+f35/fn1+fn19fn1+fX59fn19fX19fH18fXx9fH18fXx9fH18fXx8fHt8e3x7fHt8e3x7fHt8e3x7fHt8e3x7fHt8e3x7fHt8e3x8e3x7fHt8e3x7fHx8fXx9fH18fX5+fX59fn9+f35+f35/gH+Af4B/gICAgICAgICAgICAgYCBgIGAgIGAgYGBgoGCgYKBgoGCgYKBgoGCgoKDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KDgoOCg4KCgoGCgYKBgoGCgYKBgoGCgYKBgoGCgYKBgoGCgYKBgoGCgYKBgoGCgYKBgoGBgYCBgIGAgYCBgIGAgYCBgIGAgYCBgIGAgYCBgIGAgYCAgICBgIGAgYCBgIGAgYCBgIGAgYCBgExJU1RCAAAASU5GT0lDUkQMAAAAMjAwOC0wOS0yMQAASUVORwMAAAAgAAABSVNGVBYAAABTb255IFNvdW5kIEZvcmdlIDguMAAA"
download("测试.wav",'audio/wav','base64',downloadData )

参考文章

前端下载文件与读取文件内容(多种类型的文件)

修复Linux Sudo本地提权漏洞(CVE-2021-3156)

检测方法

1、以非root账户登录系统运行如下命令:

sudoedit -s /

2、若受影响,错误信息会以如下内容开头:

sudoedit:

3、若已安装补丁,错误信息会以如下内容开头:

usage:

修复方法

1.下载sudo

wget https://www.sudo.ws/dist/sudo-1.9.5p2.tar.gz sudo.tar.gz

2.解压

tar zxvf sudo.tar.gz

3.编译并安装

./configure && make && make install

参考

腾讯云安全风险通告 https://cloud.tencent.com/announce/detail/1501

使用docker 创建 Aria2

sudo mkdir -p dockercnf/aria2-config && sudo mkdir -p /downloads && sudo docker run -d --name aria2-pro --restart unless-stopped --log-opt max-size=1m -e PUID=0 -e PGID=0 -e RPC_SECRET= 你的秘钥 -p 6800:6800 -e 6888:6888 -p 6888:6888/udp -v /dockercnf/aria2-config:/config -v /downloads:/downloads p3terx/aria2-pro

无编辑器修改ubuntu源

查看当前ubuntu版本

lsb_release -a

使用阿里云镜像源,直接粘贴使用

22.04

echo "deb http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse" > /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ jammy-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse" >> /etc/apt/sources.list

20.04

echo "deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse" > /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse" >> /etc/apt/sources.list

18.04

echo "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" > /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list

16.04

echo "deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse" > /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb-src http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse" >> /etc/apt/sources.list

Axios的封装

axios封装

import axios from 'axios';

// 统一异常处理部分
function errorHandle(res) {
    switch (res.status) {
        default:
            console.log("其他错误:" + res.message)
    }
}

// 创建并配置axios实例
const instance = axios.create({
    baseURL: process.env.VUE_APP_HOST == null ? 'http://127.0.0.1/' : process.env.VUE_APP_HOST,
    // 超时 15秒
    timeout: 1000 * 15,
    // 跨域请求时是否需要使用凭证,默认为false
    withCredentials: true,
    // 请求头
    headers: {
        'Content-Type': 'application/json'
    }
});

// 请求拦截器
instance.interceptors.request.use(res => {

    // 公共参数
    const publicData = {
        time: new Date().getTime().toString().substr(0, 10),
    }

    if (res.method === 'post' || res.method === 'POST') {
        res.data = {
            ...publicData,
            ...res.data
        };
        return res;
    } else if (res.method === 'get' || res.method === 'GET') {
        res.params = {
            ...publicData,
            ...res.params
        };
        return res;
    }
});

// 响应拦截器
instance.interceptors.response.use(res => {
    if (res.status === 200 && res.data.code === 200) {
        return res.data;
    } else {
        errorHandle(res);
        return Promise.reject(res);
    }
});

export default doHttp(url = '', type = 'get', data = {}) {
    if (type === 'get' || type === 'GET') {
        return instance.get(url, {
            params: data
        });
    } else if (type === 'post' || type === 'POST') {
        return instance.post(url, data);
    }

}

gapps版本区别

如无其他需求,建议安装nano版本

aroma

  • 与 super 版所包含的 GApps 相同,但是在 Recovery 中引入了图形化界面,可以自行选择安装哪些 GApps。

super

  • 包含了所有 GApps ,像韩语日语中文拼音中文注音输入法等。(请注意:如果你是用的是基于原生的 ROM ,本版本会替换相机,通讯录等等所有有关应用)

stock

  • 类似于 Google Pixel 出厂内置的 GApps ,相比 super 版少了其他语种的输入法以及 Google 地球等。(请注意:如果你是用的是基于原生的 ROM ,本版本会替换相机,通讯录等等所有有关应用)

full

  • 与 stock 版所包含的内容相同,但此版本不会替换手机原本的应用。

mini

  • 包含基础的 Google 服务框架,以及一些影响力较大的 GApps ,相比 full 版去掉了 Docs 等应用。

micro

-包含基础的 Google 服务框架和 Gmail 等常见 GApps。

nano

  • 包含基础的 Google 服务框架,但不会有其他 不必要的 GApps。

pico

  • 包含最迷你的 Google 服务框架,但由于框架并非完整,部分 GApps可能无法运行。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.