新創酷9.99萬起售 這麼超值是要砸場子的節奏?

很久很久以前小編美美並不是做編輯而是說書的今天小編美美就來說一個古老而又神秘的故事。

很久很久以前

小編美美並不是做編輯

而是

說書的

今天小編美美就來說一個古老

而又神秘的故事

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

又大又漂亮SUV僅5.89萬?11月上市的這幾款性價比特高

4T渦輪增壓發動機,最大功率達到143馬力,匹配6速手自一體變速箱或6速手動變速箱。編者點評:新款創酷設計一下子變得年輕、運動。這樣的設計風格無疑對20多歲的朋友們更有吸引力。而且自動擋車型的起售價僅11。99萬,還採用了1。

在11月份,因為廣州車展的緣故,各大汽車廠商都在這個月里推出了今年最後一波重點新車!今天編者就和大家聊聊這個月上市的重點高性價比新SUV,要買SUV不妨多看看這些新車!

奇瑞汽車-瑞虎3x

指導價:5.89-8.09萬

奇瑞全新的小型SUV–瑞虎3x也在本月上市,5.89萬的起售價,讓很多粉絲都在後台跟我們聊過這款車。

其實瑞虎3x的車身長寬高為4200*1760*1570mm,軸距為2555mm。編者此前親身體驗過這款車的空間,它的乘坐空間夠用,基本上頭部、腿部空間都有富餘。而且後備廂的空間也不錯。

動力方面,其採用1.5L發動機最大功率106馬力,最大扭矩為135牛米。搭配4擋自動變速箱或5擋手動變速箱。

編者點評:

如果你想要買人生的第一輛車的話,瑞虎3x這一類的低價、年輕化的SUV車型可以說是比較合適的。它賣點在於不錯的外觀內飾設計、不錯的空間實用性,還有較高的性價比。另外較高的坐姿,在行車過程中也更方便察看前方的車流。

上汽通用雪佛蘭-創酷

指導價:9.99—14.99萬

在前幾天,雪佛蘭2017款創酷正式上市了。這次上市的為中期改款車型,它的外觀運用了雪佛蘭全新家族化設計,在前臉造型的變化尤為明顯!

其採用立體雙格柵的造型、修長的大燈,較老款車型更有運動感。大燈中還帶有U型LED日間行車燈,配置方面,新車提供胎壓監測、智能啟停功能、ESp、7英寸觸摸屏等亮點配置。

動力系統方面,它搭載的是1.4T渦輪增壓發動機,最大功率達到143馬力,匹配6速手自一體變速箱或6速手動變速箱。

編者點評:

新款創酷設計一下子變得年輕、運動。這樣的設計風格無疑對20多歲的朋友們更有吸引力。而且自動擋車型的起售價僅11.99萬,還採用了1.4T發動機,動力表現十分充沛。喜歡這個價位SUV車型的朋友可以多關注它!

東風標緻-標緻4008

指導價:18.57-27.37萬

因為漂亮、科幻的外觀而備受期待的法系全新SUV,標緻4008也在這個月上市!18.57-27.37萬的售價區間讓它比起翼虎、途觀這些對手車型的指導價要稍低一些。

在外觀和內飾設計方面,標緻4008足夠前衛、時尚。而在動力方面它搭載1.6T、1.8T渦輪增壓發動機,最大功率分別為167馬力、204馬力。匹配6擋手自一體變速箱!

pSA集團採用的這兩套動力系統其實在動力、平順性、油耗方面都有比較出色的表現,如果你需求動力充沛、提速給力的車型,標緻4008可以成為你重點考慮的車型之一。

編者點評:

外觀和內飾的超前的設計、三大件不錯的性能,讓標緻4008的競爭力表現不錯。雖然低配車型的舒適性配置有些缺失,但是其安全性配置還是很厚道的,所以不失為一款競爭力出色的歐系SUV。

最後總結:

上面提到的車型都是本月已經上市的高關注度SUV車型,在性價比方面都表現不錯,而我個人比較喜歡標緻4008,前衛的設計和不錯的操控性是它能打動我的地方!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

一文了解Docker容器技術的操作

一文了解Docker容器技術的操作

前言一、Docker是什麼二、Docker的安裝及測試Docker的安裝Docker的Hello world測試三、Docker的常見操作鏡像的基本操作容器的基本操作鏡像、容器的導入和導出四、關於DockerFile總結

前言

相信點進這篇文章的Coder,不管是在各大技術論壇上、技術交流群,亦或招聘網上,應該都有見到過Doker容器技術的面孔,隨着社會節奏的加快以及迫於生活的壓力,在計算機技術日新月異的今天,真正能夠沉下心來學習一門技術的時間真的不多。趁着這段空閑的時間,濤耶也該是時候把過去學習時所積累的筆記沉澱一下了。本文主要是從是什麼、為什麼、怎麼做的角度來介紹Docker容器技術的入門,能讓初次接觸Docker容器技術的朋友更快更便捷的使用Docker。

一、Docker是什麼

對於Docker,官方的介紹如下:

Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中,然後發布到任何流行的 Linux或Windows機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何接口。

在實際的開發過程中,我們往往會因為環境的搭建而浪費過多的時間,而現如今有了Docker容器技術的支持,我們不再過於擔心各種因為環境問題而造成的過多時間的浪費。Docker容器引擎中已經為我們提供了開發過程中所需要的各種鏡像,我們需要有Resid數據庫、Elasticsearch搜索技術、Mq消息隊列等支持,我們都可以使用Docker中的pull命令來從中央倉庫中進行拉取,而不像傳統那樣從各大官網亦或github中進行下載。讀到這裏的朋友應該會有所發現,Docker就有點類似Maven管理工具,或者直接將Docker看做一個裝載了大量“物資”的集裝箱,但Docker的強大之處可並不止步於此,查閱了解后,Docker主要有以下幾大特性:

  • Automating the packaging and deployment of applications(使應用的打包與部署自動化)
  • Creation of lightweight, private PAAS environments(創建輕量、私密的PAAS環境)
  • Automated testing and continuous integration/deployment(實現自動化測試和持續的集成/部署)
  • Deploying and scaling web apps, databases and backend services(部署與擴展webapp、數據庫和後台服務)

總之,Docker容器是現如今相當火熱的一門技術。之前讀到網上有着這麼一句話:電腦如果有問題,沒有是重裝系統解決不了的。話雖如此,但是一旦重裝系統之後,我們之前系統中所有保存資源都被消除了,我們需要使用QQ增進朋友之間的感情,則要到鵝廠中去下載、安裝;需要網易雲音樂來放鬆心情,則要到官網中安裝、下載,以及需要下載並安裝其他各大軟件才能滿足自己的實際需求,一個不小心還可能會綁架其他垃圾軟件。當然有的朋友會在重裝系統之前自己的資源備份以下,重裝系統之後再直接使用,但依然免不了N個下一步所帶來的時間消耗。假如現在有這麼一個容器,裏面存放着我們需要的所有資源,在我們需要的時候只需要一行簡單的pull命令即可迅速完成所有軟件的下載安裝步驟,這豈不美哉!

沒錯,Docker容器就是基於這麼一個思想來解決我們各大煩惱。如果對於Docker容器技術的理解還不是特別清楚,可拜讀一下大佬的文章:漫畫 | 從搬家到容器技術 Docker 應用場景解析,這篇文章使用漫畫的形式來給讀者介紹Docker容器的優勢。

二、Docker的安裝及測試

Docker的安裝

我們往往是使用Linux系統來安裝Docker,在之前的文章也有過Linux系統的安裝,這裏就不多介紹了。下面我們就在CentOS Linux release 8.0.1905 (Core)系統下來安裝一下Docker吧。

首選使用cat /etc/redhat-release查看一下自己的Linux版本:

[root@iZm5eei156c9h3hrdjpe77Z ~]# cat /etc/redhat-release
CentOS Linux release 8.0.1905 (Core)

在安裝Docker之前,我們先把yum更新一下

update yum

安裝Docker需要的軟件包

yum install -y yum-utils device-mapper-persistent-data lvm2

設置一下docker的yum源,後期在使用的Docker的pull操作都是在此倉庫中下載

 yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

查看倉庫中所有的docker版本,以便安裝我們需要的Docker版本

yum list docker-ce --showduplicates | sort -r

安裝需要的docker版本,此處以Docker17.12.1版本為例

yum install docker-ce-17.12.1.ce

成功安裝之後,便可使用docker version/docker -v即可查看所安裝docker的版本

# docker version
[root@iZm5eei156c9h3hrdjpe77Z ~]# docker version
Client:
 Version:    17.12.1-ce
 API version:    1.35
 Go version:    go1.9.4
 Git commit:    7390fc6
 Built:    Tue Feb 27 22:15:20 2018
 OS/Arch:    linux/amd64

Server:
 Engine:
  Version:    17.12.1-ce
  API version:    1.35 (minimum version 1.12)
  Go version:    go1.9.4
  Git commit:    7390fc6
  Built:    Tue Feb 27 22:17:54 2018
  OS/Arch:    linux/amd64
  Experimental:    false

# docker -v
[root@iZm5eei156c9h3hrdjpe77Z ~]# docker -v
Docker version 17.12.1-ce, build 7390fc6

之後,我們需要更換docker拉取軟件的服務,這裏使用的是Aliyun鏡像加速器,使用加速器可以提升獲取Docker官方鏡像的速度(一下操作可直接複製執行):

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://1ewanek5.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

這樣一來,我們便完整的安裝好了Docker。(PS:由於系統環境的問題,在安裝過程中可能需要到其他依賴,只需要根據提示操作即可)

Docker的Hello world測試

任何技術的學習,我們都離不開Hello world,Docker也不例外,下面我們來使用Docker來運行一下Hello world吧,在測試之前我們首先使用如下命令來啟動Docker,啟動、重新啟動以及設置開機自啟動:

# Docker的啟動
systemctl start docker
# Docker的重啟
systemctl restart docker
# Docker的開機自啟動
systemctl enable docker     # 一般我們使用開機自啟動的形式

啟動好Docker之後,我們來在Docker中運行一下hello world:

# docker 運行hello world
docker run hello-world

在我們執行docker run hello-world之後,Docker首先會根據我們的命令查看一下本地是否存在hello-world鏡像,如果存在則會直接運行,如果不存在就會去中央倉庫中拉取(下載)hello-world鏡像(拉取過程極為迅速)之後再來運行。由於我們首次使用Docker,所以執行之後會出現以下結果:

由於Docker已經幫我們拉取了hello-world鏡像,所以當我們再次運行docker run hello-world之後,則會出現如下結果:

順便一提,我們在使用Docker拉取所拉取的所有鏡像都來源於Docker的中央倉庫,裏面存放了大量的鏡像可供我們自由使用:https://hub.docker.com/

三、Docker的常見操作

啟動docker systemctl start docker,重啟systemctl restart docker,開機docker自啟動systemctl enable docker

# Docker的啟動
systemctl start docker
# Docker的重啟
systemctl restart docker
# Docker的開機自啟動
systemctl enable docker     # 一般我們使用開機自啟動的形式

鏡像的基本操作

  • 使用search命令來檢索中央倉庫中收錄的鏡像,這裏以tomcat為例
# 檢索鏡像:docker search [鏡像名稱]
docker search tomcat

  • 拉取(下載)鏡像:docker pull tomcat(默認最新版本),如果需要其他版本可在中央倉庫中查閱
# 拉取鏡像:docker pull [鏡像名稱]
docker pull tomcat
# 默認拉取的是最新版本,如果需要特定版本,在後面指定即可,以tomcat7.0.1為例
docker pull tomcat:7.0.1
  • 查看已經下載的本地鏡像:
# 查看已經下載的本地鏡像
docker images

  • 刪除本地鏡像
# 刪除本地鏡像: docker rmi 鏡像名稱/IMAGE ID
docker rmi tomcat

容器的基本操作

  • 根據鏡像啟動對應的容器
# 根據鏡像啟動對應的容器
docker run -d --name mytomcat tomcat
# --name 對容器起一個別名
# -d 對指定的容器進行後台運行
  • 停止運行的容器
# 停止運行的容器:docker stop 容器名稱/CONTAINER ID
docker stop mytomcat
  • 查看正在運行的容器
docker ps       # 查看正在運行的容器
docker ps -a    # 查看本地所有的容器
  • 刪除容器
# 注:刪除容器是使用rm,刪除鏡像是rmi,且刪除鏡像之前需要停止運行容器並刪除
docker rm mytomcat
  • 啟動一個做了端口映射的容器,在之前創建容器之後,我們無法通過ip:端口的形式來訪問Docker中所開啟的服務,因為每一個容器他都是獨立,所以要想訪問,我們則需要通過端口的映射來訪問容器。
docker run -d --name mytomcat -p 8888:8080 tomcat
# --name:對容器起一個別名
# -p:將主機的端口映射到容器的一個端口  主機端口:容器內部的端口 
# -d:後台運行
  • 查看容器的日誌docker logs mytomcat

  • 容器開機自起動:

docker update mytomcat --restart=always
  • 進入對應的容器
docker exec -it mytomcat /bin/bash
  • 本地文件(是centos不是windows)與docker容器中文件之間的互傳,以將ik分詞器插件上傳至elasticsearch容器為例:
# 先將windows上的文件使用xftp上傳到vmware linux中,然後將文件使用docker命令上傳到docker容器中
# docker cp 本地路徑 容器名:容器路徑
docker cp ./elasticsearch-analysis-ik-6.5.4.zip elasticsearch:/usr/share/elasticsearch/plugins
  • 文件的掛載

Docker容器是獨立,且其相當於是一個及其精簡版的Linux,在我們通過exec命令之後,我們是無法使用vim、vi等命令來對其內部文件進行編輯,在一般情況下我們在創建好容器之後一般會對其配置文件進行編輯,此時我們可以使用Docker中的掛載來將容器內文件掛載到宿主機中。當我們在宿主機中對掛載的文件進行編輯的時候,容器中所被掛載的文件也會做出相應的修改,下面就是docker掛載文件的-v操作(以掛載Es的配置文件和數據文件為例):

mkdir -p ./resources/elasticsearch/config
mkdir -p ./resources/elasticsearch/data

docker run --name elasticsearch -p 9200:9200 \
-e "discovery.type=single-node" \
-e ES_JAVA_OPTS="-Xms256m -Xmx256m" \
-v /resources/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \
-v /resources/elasticsearch/data:/usr/share/elasticsearch/data -d elasticsearch:5.6.8

鏡像、容器的導入和導出

export:可將docker容器通過export導出為tar文件

docker export mytomcat > mytomcat.tar

import:基於tar文件來創建一個新的鏡像

docker import - mytomcat < mytomcat.tar

注:以上指示Docker容器中常用的一些命令,對於不同的鏡像的使用,其啟動命令也是會有所區別,後面的一些命令會在使用的時候進行介紹,其他更多Docker操作可參考Docker官方文檔:
https://docs.docker.com/engine/reference/commandline/docker/

四、關於DockerFile

上面我們已經介紹了Docker以及在使用Docker過程中常用的一些命令。而本小結將會介紹Dockerfile,Dockerfile是常用的一種創建鏡像的方式,由file我們也不難知道Dockerfile就是一個Docker文件,可以簡單把它理解成在其內部定義了構建Docker容器的一條條指令,而每一條指令的內容都代表了構建容器的每個流程,Docker通過讀取Dockerfile內的每條指令來構建鏡像。下面我們將會簡單介紹編寫Dockerfile的常用指令及其搭建流程,並最終使用Dockerfile來搭建一個centos鏡像。(PS:本文中的Dockerfile僅僅是簡單介紹,之後Dockerfile的詳細編寫會單獨成文整理)

Dockerfile官方文檔:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

在介紹Dockerfile之前,我們首先通過下面這張圖來直觀的了解下Dockerfile(來源網絡,侵刪。)

從上圖我們可以大致了解Dockerfile的編寫流程,一個標準的Dockerfile以FROM指令開頭(除註釋之外,註釋通過#進行),一般來說,Dockerfile中的指令主要包括四種類型,該四種類型也就是編寫Dockerfile的一般流程:

  • 指定構建新鏡像的基礎鏡像(父鏡像):FROM
  • 說明所構建鏡像的維護者信息:MAINTAINER(官方已經不贊成使用)、LABEL(建議使用)
  • 對鏡像的操作指令:RUN、ENV、ADD、COPY以及WORKDIR
  • 對容器的啟動指令:CMD、ENTRYPOINT、USER

下面我們通過Dockerfile的形式來搭建一個nginx容器,並訪問其index.html頁面。

創建一個工作目錄,用於指定創建新鏡像的所需要的文件(不做要求,但卻是一種創建鏡像的規範)

mkdir demo_dockerfile
cd demo_dockerfile
vim Dockerfile

編寫Dockerfile文件

FROM nginx
LABEL author=taoye email=26647879@qq.com desc="Hello Dockerfile, I am a coder."

Dockerfile文件寫完之後,我們通過該文件來創建一個新的鏡像,-t參數用於指定創建新鏡像的倉庫和名稱,並設置版本,注意在結尾有.,表示的是指定構建新鏡像過程中的上下文環境的目錄。

docker build -t demo_nginx/demo_dockerfile:v1.0 .

執行之後docker build之後便會在本地創建了一個新的鏡像,我們可以通過該鏡像來創建容器並使用curl來進行測試

docker run --name demo_nginx -d -p 7777:80 demo_nginx/demo_dockerfile:v1.0

curl localhost:7777

總結

本文首先介紹的是對Docker基本認識,其次詳細說明了Docker環境的搭建,之後常見的Docker操作,最後簡單介紹了Dockerfile及通過Dockerfile創建一個簡單nginx容器。在之後文章中會詳細介紹Dockerfile,最好的學習方式莫過於從官方文檔中盡情的無償汲取知識,本文說到底僅僅是在學習Docker官方文檔之後的一個簡單總結,所涉及到的也只是冰山一角。Docker官方文檔中包含了詳細且全面的介紹,涉及到Docker的方方面面,有條件的朋友強烈建議閱讀耐心地閱讀官方文檔:http://docs.docker.com/engine/reference/builder/

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

IUCN:亞當峰朝聖者腳下 斯里蘭卡瀕危兩棲類正在消失

環境資訊中心綜合外電;黃鈺婷 翻譯;林大利 審校;稿源:Mongabay

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

英封城期間 販賣機賣肉和菜、直接向漁夫買 掀新商機

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

印度全國封鎖後 恆河上游部分河段可飲用

摘錄自2020年4月24日中央社報導

一般帶大量超級細菌的恆河,在印度全國封鎖近一個月後,因為幾乎沒有人類污染,瑜伽聖城瑞詩凱詩(Rishikesh)這段恆河河水,經政府檢測水質達到可飲用的標準。

印度北部北阿坎德省(Uttarakhand)污染控制局最近從瑞詩凱詩及哈里德瓦(Haridwar)的恆河河段抽樣進行化驗,發現水質可以飲用。

官方報告表示,哈基寶里河壇段的恆河水,生化需氧量(Biochemical oxygen demand)也下降20%。專家說,這意味著恆河水含氧量變高,水族可舒適地在河中呼吸。

印度中央污染控制局(Central Pollution Control Board)近日發表的調查報告顯示,恆河36個監測站中,有27個監測站測得恆河水質已變為可安全沐浴和水中生物可安全生活的水準。

生活環境
土地水文
土地利用
國際新聞
印度
封城
武漢肺炎
恆河

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

冷空氣來臨 開上這些車秋褲都不用穿就能度過寒冬

28-15。88萬長安CS75可謂算得上自主SUV老牌勁旅中的一員了,整體外觀很硬派卻又不失時尚,天使眼造型的大燈犀利又帥氣。內飾整體是家族式的設計,1。5T車型全系標配了自動啟停功能,還有自動駐車、無鑰匙進入/啟動、倒車影像、感應雨刷等配置一應俱全。

又到了冷空氣入侵的時候了,你媽媽有沒有喊你穿秋褲呢,雖然南方的小夥伴還可以沐浴在溫暖的陽光中,但是北方的小夥伴們已經在激烈的雪球大戰中了,凍成狗的小學生都裹着棉被去上學了。

擠公交地鐵上班的就稍微沒那麼難受了,起碼不會再穩到那股難聞的汗酸味,最舒服的要數開車上班的孩子了,風吹日晒雨淋完全沒關係,不過一些沒有座椅加熱的真皮座椅還是給人冰涼涼的感覺。

廣汽乘用車-傳祺GA6

指導價:10.28-19.68萬

說起自主品牌中型車,傳祺GA6絕對是一款代表作,車身造型有很強的設計感,凌雲翼家族式設計元素,圓潤飽滿的大燈有着很高的辨識度;內飾的設計布局和做工有着堪比合資車的水準,配置上無鑰匙進入/啟動、自動駐車、上坡輔助、方向盤換擋等配置非常豐富。

4850×1830×1485mm的車身尺寸,軸距2720mm,乘坐空間表現良好,儲物空間設計很人性化,隨手可及;有着阿爾法羅密歐技術調校的底盤是一大亮點,行駛品質在自主品牌車型中屬於一流水平,1.5T(最大功率152馬力)+7擋雙離合的動力組合兼顧了動力和燃油經濟性,是比較實惠的一款車型。

一汽奔騰-奔騰B70

指導價:9.98-14.98萬

奔騰B70改款後設計風格上有了明顯的轉變,時尚動感的外觀視覺效果上還是相當吸引人的,熏黑的尾燈、黑色車頂、后擾流板彰顯了其運動氣息;搪塑工藝處理的中控台質感出色,中控屏波浪開口設計很個性化,黑色內飾搭配紅色縫線的設計突出了運動氛圍。

長*寬*高為4800*1820*1472mm,軸距達到了2725mm,最具亮點的就是它使用了與馬自達6相同的動力系統和底盤,技術成熟,開起來有合資車的感覺,1.8T(最大功率186馬力)+6擋手自一體變速器的組合動力響應很积極,轉向精準,車身緊湊底盤硬朗,懸挂支撐到位,操控感覺非常棒。

長安汽車-長安CS75

指導價:9.28-15.88萬

長安CS75可謂算得上自主SUV老牌勁旅中的一員了,整體外觀很硬派卻又不失時尚,天使眼造型的大燈犀利又帥氣;內飾整體是家族式的設計,1.5T車型全系標配了自動啟停功能,還有自動駐車、無鑰匙進入/啟動、倒車影像、感應雨刷等配置一應俱全。

新推出的1.5T(最大功率170馬力)車型動力表現已經超越2.0L(最大功率158馬力)發動機的表現,低扭表現相當出色,輕鬆帶動1.6噸的車身,動力輸出的線性程度堪比自然吸氣發動機,齒比設定相對密集的6擋手動變速器使得各個擋位的動力銜接更加順暢,唯一比較遺憾的就是1.5T車型暫時沒配備自動變速器了。

長城汽車-哈弗H2

指導價:8.68-12.88萬

紅藍雙標的戰略在哈弗H2看來是非常的成功的,藍標外觀更加年輕時尚化,紅標側重豪華家用,適合不同人群的需求;內飾無論是做工還是用料都給人很豪華的感覺,配置上也是越級的享受,自動頭燈、車內氛圍燈、倒車影像、定速巡航、陡坡緩降等配置在一款11萬的車型都能擁有。

其車身尺寸為4335*1814*1695mm,顯得比較緊湊,2560mm的軸距帶來的空間感受並不會感到擁擠,大量皮革包裹的門邊觸感良好;動力上依舊是我們熟悉的1.5T(最大功率150馬力)發動機,搭配6AT/6MT,起步輕鬆,渦輪介入後勁足,整體加速較為線性。

總結:自主車型現在無論是外觀還是內飾配置,相比於合資車都有很大的優勢,三大件方面質量也在逐步提高,尤其是哈弗品牌車型,個個都內外兼修,自主品牌已經有了非常大的提升了,值得入手。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※台北網頁設計公司全省服務真心推薦

※想知道最厲害的網頁設計公司"嚨底家"!

※推薦評價好的iphone維修中心

網頁設計最專業,超強功能平台可客製化

※別再煩惱如何寫文案,掌握八大原則!

一次找出範圍內的所有素數,埃式篩法是什麼神仙算法?

本文始發於個人公眾號:TechFlow,原創不易,求個關注

今天這篇是算法與數據結構專題的第23篇文章,我們繼續數論相關的算法,來看看大名鼎鼎的埃式篩法。

我們都知道在數學領域,素數非常重要,有海量的公式和研究關於素數,比如那個非常著名至今沒有人解出來的哥德巴赫猜想。和數學領域一樣,素數在信息領域也非常重要,有着大量的應用。舉個簡單的例子,很多安全加密算法也是利用的質數。我們想要利用素數去進行各種計算之前,總是要先找到素數。所以這就有了一個最簡單也最不簡單的問題,我們怎麼樣來尋找素數呢?

判斷素數

尋找素數最樸素的方法當然是一個一個遍歷,我們依次遍歷每一個數,然後分別判斷是否是素數。所以問題的核心又回到了判斷素數上,那麼怎麼判斷一個數是不是素數呢?

素數的性質只有一個,就是只有1和它本身這兩個因數,我們要判斷素數也只能利用這個性質。所以可以想到,假如我們要判斷n是否是素數,可以從2開始遍歷到n-1,如果這n-1個數都不能整除n,那麼說明n就是素數。這個我沒記錯在C語言的練習題當中出現過,總之非常簡單,可以說是最簡單的算法了。

def is_prime(n):
    for i in range(2, n):
        if n % i == 0:
            return False
    return n != 1

顯然,這個算法是可以優化的,比如當n是偶數的時候,我們根本不需要循環,除了2意外的偶數一定是合數。再比如,我們循環的上界其實也沒有必要到n-1,到就可以了。因為因數如果存在一定是成對出現的,如果存在小於根號n的因數,那麼n除以它一定大於根號n。

這個改進也很簡單,稍作改動即可:

def is_prime(n):
    if n % 2 == 0 and n != 2:
        return False
    for i in range(3, int(math.sqrt(n) + 1)):
        if n % i == 0:
            return False
    return n != 1

這樣我們把O(n)的算法優化到了O()也算是有了很大的改進了,但是還沒有結束,我們還可以繼續優化。數學上有一個定理,只有形如6n-1和6n+1的自然數可能是素數,這裏的n是大於等於1的整數。

這個定理乍一看好像很高級,但其實很簡單,因為所有自然數都可以寫成6n,6n+1,6n+2,6n+3,6n+4,6n+5這6種,其中6n,6n+2,6n+4是偶數,一定不是素數。6n+3可以寫成3(2n+1),顯然也不是素數,所以只有可能6n+1和6n+5可能是素數。6n+5等價於6n-1,所以我們一般寫成6n-1和6n+1。

利用這個定理,我們的代碼可以進一步優化:

def is_prime(n):
    if n % 6 not in (1, 5) and n not in (2, 3):
        return False
    for i in range(3, int(math.sqrt(n) + 1)):
        if n % i == 0:
            return False
    return n != 1

雖然這樣已經很快了,但仍然不是最優的,尤其是當我們需要尋找大量素數的時候,仍會消耗大量的時間。那麼有沒有什麼辦法可以批量查找素數呢?

有,這個方法叫做埃拉托斯特尼算法。這個名字念起來非常拗口,這是一個古希臘的名字。此人是個古希臘的大牛,是大名鼎鼎的阿基米德的好友。他雖然沒有阿基米德那麼出名,但是也非常非常厲害,在數學、天文學、地理學、文學、歷史學等多個領域都有建樹。並且還自創方法測量了地球直徑、地月距離、地日距離以及黃赤交角等諸多數值。要知道他生活的年代是兩千五百多年前,那時候中國還是春秋戰國時期,可以想見此人有多厲害。

埃式篩法

我們今天要介紹的埃拉托斯特尼算法就是他發明的用來篩選素數的方法,為了方便我們一般簡稱為埃式篩法或者篩法。埃式篩法的思路非常簡單,就是用已經篩選出來的素數去過濾所有能夠被它整除的數。這些素數就像是篩子一樣去過濾自然數,最後被篩剩下的數自然就是不能被前面素數整除的數,根據素數的定義,這些剩下的數也是素數。

舉個例子,比如我們要篩選出100以內的所有素數,我們知道2是最小的素數,我們先用2可以篩掉所有的偶數。然後往後遍歷到3,3是被2篩剩下的第一個數,也是素數,我們再用3去篩除所有能被3整除的數。篩完之後我們繼續往後遍歷,第一個遇到的數是7,所以7也是素數,我們再重複以上的過程,直到遍歷結束為止。結束的時候,我們就獲得了100以內的所有素數。

如果還不太明白,可以看下下面這張動圖,非常清楚地還原了這整個過程。

不見圖 請翻牆

這個思想非常簡單,理解了之後寫出代碼來真的很容易:

def eratosthenes(n):
    primes = []
    is_prime = [True] * (n + 1)
    for i in range(2, n+1):
        if is_prime[i]:
            primes.append(i)
            # 用當前素數i去篩掉所有能被它整除的數
            for j in range(i * 2, n+1, i):
                is_prime[j] = False
    return primes

我們運行一次代碼看看:

和我們的預期一樣,獲得了小於100的所有素數。我們來分析一下篩法的複雜度,從代碼當中我們可以看到,我們一共有了兩層循環,最外面一層循環固定是遍歷n次。而裏面的這一層循環遍歷的次數一直在變化,並且它的運算次數和素數的大小相關,看起來似乎不太方便計算。實際上是可以的,根據素數分佈定理以及一系列複雜的運算(相信我,你們不會感興趣的),我們是可以得出篩法的複雜度是

極致優化

篩法的複雜度已經非常近似了,因為即使在n很大的時候,經過兩次ln的計算,也非常近似常數了,實際上在絕大多數使用場景當中,上面的算法已經足夠應用了。

但是仍然有大牛不知滿足,繼續對算法做出了優化,將其優化到了的複雜度。雖然從效率上來看並沒有數量級的提升,但是應用到的思想非常巧妙,值得我們學習。在我們理解這個優化之前,先來看看之前的篩法還有什麼可以優化的地方。比較明顯地可以看出來,對於一個合數而言,它可能會被多個素數篩去。比如38,它有2和19這兩個素因數,那麼它就會被置為兩次False,這就帶來了額外的開銷,如果對於每一個合數我們只更新一次,那麼是不是就能優化到了呢?

怎麼樣保證每個合數只被更新一次呢?這裏要用到一個定理,就是每個合數分解質因數只有的結果是唯一的。既然是唯一的,那麼一定可以找到最小的質因數,如果我們能夠保證一個合數只會被它最小的質因數更新為False,那麼整個優化就完成了。

那我們具體怎麼做呢?其實也不難,我們假設整數n的最小質因數是m,那麼我們用小於m的素數i乘上n可以得到一個合數。我們將這個合數消除,對於這個合數而言,i一定是它最小的質因數。因為它等於i * n,n最小的質因數是m,i 又小於m,所以i是它最小的質因數,我們用這樣的方法來生成消除的合數,這樣來保證每個合數只會被它最小的質因數消除。

根據這一點,我們可以寫出新的代碼:

def ertosthenes(n):
    primes = []
    is_prime = [True] * (n+1)
    for i in range(2, n+1):
        if is_prime[i]:
            primes.append(i)
        for j, p in enumerate(primes):
            # 防止越界
            if p > n // i:
                break
            # 過濾
   is_prime[i * p] = False
            # 當i % p等於0的時候說明p就是i最小的質因數
            if i % p == 0:
                break
                
    return primes

總結

到這裏,我們關於埃式篩法的介紹就告一段落了。埃式篩法的優化版本相對來說要難以記憶一些,如果記不住的話,可以就只使用優化之前的版本,兩者的效率相差並不大,完全在可以接受的範圍之內。

篩法看着代碼非常簡單,但是非常重要,有了它,我們就可以在短時間內獲得大量的素數,快速地獲得一個素數表。有了素數表之後,很多問題就簡單許多了,比如因數分解的問題,比如信息加密的問題等等。我每次回顧篩法算法的時候都會忍不住感慨,這個兩千多年前被發明出來的算法至今看來非但不過時,仍然還是那麼巧妙。希望大家都能懷着崇敬的心情,理解算法當中的精髓。

如果喜歡本文,可以的話,請點個關注,給我一點鼓勵,也方便獲取更多文章。

本文使用 mdnice 排版

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計最專業,超強功能平台可客製化

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家公司費用怎麼算?

容器技術之Docker私有鏡像倉庫docker-distribution

  在前邊的博客中我們說到docker的架構由docker客戶端、服務端以及倉庫組成;docker倉庫就是用來存放鏡像的地方;其實docker registry我們理解為存放docker鏡像倉庫的倉庫比較準確吧;因為docker的鏡像倉庫通常是把同一類的鏡像用不同的版本來區別,而registry則是用來存放這些倉庫的倉庫;默認安裝docker都是從dockerhub鏡像倉庫下載鏡像;其實在生產環境中,我們很少去公有倉庫上下載鏡像,原因之一是公有倉庫中的鏡像在生產環境中使用,有些不適配,通常我們是去公有倉庫下載基礎鏡像,然後基於基礎鏡像構建適合自己生產環境中的鏡像;其次公有倉庫鏡像有很多都不是安全的鏡像,這麼說吧,我們不確定自己下載的鏡像是否有後門,是否有挖礦代碼,所以基於種種因素,我們還是有必要搭建自己私有的鏡像倉庫;今天我們就來聊一聊docker的私有鏡像倉庫的搭建;

  1、查看docker-distribution包簡介

[root@docker_registry ~]# yum info docker-distribution
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
Available Packages
Name        : docker-distribution
Arch        : x86_64
Version     : 2.6.2
Release     : 2.git48294d9.el7
Size        : 3.5 M
Repo        : extras/7/x86_64
Summary     : Docker toolset to pack, ship, store, and deliver content
URL         : https://github.com/docker/distribution
License     : ASL 2.0
Description : Docker toolset to pack, ship, store, and deliver content

[root@docker_registry ~]# 

  提示:docker-distribution這個包就是提供簡單倉庫服務軟件實現;

  2、安裝docker-distribution

[root@docker_registry ~]# yum install -y docker-distribution
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
Resolving Dependencies
There are unfinished transactions remaining. You might consider running yum-complete-transaction, or "yum-complete-transaction --cleanup-only" and "yum history redo last", first to finish them. If those don't work you'll have to try removing/installing packages by hand (maybe package-cleanup can help).
The program yum-complete-transaction is found in the yum-utils package.
--> Running transaction check
---> Package docker-distribution.x86_64 0:2.6.2-2.git48294d9.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

===================================================================================================================
 Package                         Arch               Version                               Repository          Size
===================================================================================================================
Installing:
 docker-distribution             x86_64             2.6.2-2.git48294d9.el7                extras             3.5 M

Transaction Summary
===================================================================================================================
Install  1 Package

Total download size: 3.5 M
Installed size: 12 M
Downloading packages:
docker-distribution-2.6.2-2.git48294d9.el7.x86_64.rpm                                       | 3.5 MB  00:00:03     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : docker-distribution-2.6.2-2.git48294d9.el7.x86_64                                               1/1 
  Verifying  : docker-distribution-2.6.2-2.git48294d9.el7.x86_64                                               1/1 

Installed:
  docker-distribution.x86_64 0:2.6.2-2.git48294d9.el7                                                              

Complete!
[root@docker_registry ~]# 

  3、查看docker-distribution安裝了那些文件

[root@docker_registry ~]# rpm -ql docker-distribution
/etc/docker-distribution/registry/config.yml
/usr/bin/registry
/usr/lib/systemd/system/docker-distribution.service
/usr/share/doc/docker-distribution-2.6.2
/usr/share/doc/docker-distribution-2.6.2/AUTHORS
/usr/share/doc/docker-distribution-2.6.2/CONTRIBUTING.md
/usr/share/doc/docker-distribution-2.6.2/LICENSE
/usr/share/doc/docker-distribution-2.6.2/MAINTAINERS
/usr/share/doc/docker-distribution-2.6.2/README.md
/var/lib/registry
[root@docker_registry ~]# 

  提示:/etc/docker-distribution/registry/config.yml這個文件用於配置registry的配置文件;/usr/bin/registry是二進制應用程序;/usr/lib/systemd/system/docker-distribution.service 這個文件是docker-distribution的unit file;/var/lib/registry這個目錄用於存放我們上傳到registry上的鏡像存放地;

  4、查看配置文件

[root@docker_registry ~]# cat /etc/docker-distribution/registry/config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
    cache:
        layerinfo: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
http:
    addr: :5000
[root@docker_registry ~]# 

  提示:這個配置文件是一個yml語法的配置文件,從上面的信息可以看到,默認情況docker-distribution監聽在tcp的5000端口;存放鏡像的目錄是/var/lib/registry/目錄下;

  5、啟動docker-distribution

[root@docker_registry ~]# systemctl start docker-distribution
[root@docker_registry ~]# ss -tnl
State       Recv-Q Send-Q            Local Address:Port                           Peer Address:Port              
LISTEN      0      128                           *:22                                        *:*                  
LISTEN      0      100                   127.0.0.1:25                                        *:*                  
LISTEN      0      128                          :::22                                       :::*                  
LISTEN      0      100                         ::1:25                                       :::*                  
LISTEN      0      128                          :::5000                                     :::*                  
[root@docker_registry ~]# 

  提示:可以看到5000端口已經處於監聽狀態了;到此docker-distribution就啟動起來了;這個倉庫服務很簡陋,沒有用戶認證功能,默認是基於http通信而非https,所以從某些角度講,不是一個安全的倉庫;所以一般不見在互聯網上使用,在自己的內外環境中可以使用;

  這裏補充一點,docker的鏡像通常是 registry地址加repository名稱加版本這三部分組成,registry可以是域名,可以是ip地址加端口,也可以說域名加端口,默認https是443端口,http是80端口,如果不寫端口默認是443而非80(原因是docker默認不支持從http協議的倉庫下載/上傳鏡像);例如 quay.io/coreos/flannel:v0.12.0-s390x  從這個鏡像名我們就可以知道registry是https://quay.io;repository名稱為coreos/flannel 版本是v0.12.0-s390x;

  示例:下載第三方倉庫鏡像到本地

  提示:可以看到下載下來的鏡像名稱就是我們剛才說的registry+repository+版本;從上面的信息我們可以總結一點,docker鏡像的名稱(標籤)反應了該鏡像來自哪個registry的那個倉庫;所以我們要下載私有鏡像倉庫中的鏡像就需要把加上私有registry的名稱或地址+repository+版本來下載私有鏡像倉庫中的鏡像;同理上傳鏡像也需要寫明上傳到那個registry中的那個repository中去;

  示例:上傳本地鏡像到私有倉庫

  提示:要把本地倉庫鏡像傳到私有倉庫中去,首先我們要把本地鏡像打一個新的標籤,按照我們剛才上面說的邏輯,然後在上傳新打到標籤的鏡像到私有倉庫就可以了;從上面的信息我們看到當我們打好標籤后,上傳鏡像時報錯了,提示我們倉庫不是https的;默認情況docker不支持http明文上傳/下載鏡像;如果我們非要用http上傳下載鏡像我們需要在配置文件中明確的告訴docker非安全倉庫地址;

  配置docker支持私有倉庫上傳下載鏡像

[root@docker_registry ~]# cat /etc/docker/daemon.json
{
        "registry-mirrors": ["https://registry.docker-cn.com","https://cyr1uljt.mirror.aliyuncs.com"],
        "insecure-registries": ["192.168.0.99:5000"]
}

[root@docker_registry ~]# systemctl daemon-reload    
[root@docker_registry ~]# systemctl restart docker 

  提示:我們通過在配置文件中配置insecure-registries來告訴docker192.168.0.99:5000這個registry是不安全的,但是我們信任這個倉庫,大概就是這個意思嘛;通常我們是寫主機名然後配合hosts文件來解析的方式來對registry解析;從而把鏡像命名為主機名+倉庫名+版本的形式;如下所示;這裏還需要注意一點insecure-registries後面的列表中的倉庫如果有域名,域名不能有下劃線(“_”),否則重啟docker會起不來;

[root@docker_registry ~]# cat /etc/docker/daemon.json 
{
        "registry-mirrors": ["https://registry.docker-cn.com","https://cyr1uljt.mirror.aliyuncs.com"],
        "insecure-registries": ["192.168.0.99:5000","docker-registry.io:5000"]

}
[root@docker_registry ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.0.99 docker-registry.io registry
192.168.0.22 docker-node01.io node01
192.168.0.23 docker-node02.io node02
[root@docker_registry ~]# systemctl restart docker
[root@docker_registry ~]# docker info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 1
 Server Version: 19.03.11
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 3.10.0-693.el7.x86_64
 Operating System: CentOS Linux 7 (Core)
 OSType: linux
 Architecture: x86_64
 CPUs: 4
 Total Memory: 1.785GiB
 Name: docker_registry
 ID: R34V:IG2F:23I6:6WG6:FFQ4:75SV:3UKZ:RFH7:DGCO:QS7V:CS7K:NSH6
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Registry: https://index.docker.io/v1/
 Labels:
 Experimental: false
 Insecure Registries:
  192.168.0.99:5000
  docker-registry.io:5000
  127.0.0.0/8
 Registry Mirrors:
  https://registry.docker-cn.com/
  https://cyr1uljt.mirror.aliyuncs.com/
 Live Restore Enabled: false

[root@docker_registry ~]#

  提示:重啟docker后,如果在docker info 中能夠看到我們配置的內容說明配置生效了;現在我們再來傳我們新打的標籤的鏡像,看看是否能夠傳到我們的私有倉庫呢?

[root@docker_registry ~]# docker images
REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
docker-registry.io:5000/centos   7                   b5b4d78bc90c        4 weeks ago         203MB
centos                           7                   b5b4d78bc90c        4 weeks ago         203MB
192.168.0.99:5000/flannel        v0.12.0-s390x       57eade024bfb        2 months ago        56.9MB
quay.io/coreos/flannel           v0.12.0-s390x       57eade024bfb        2 months ago        56.9MB
[root@docker_registry ~]# docker push 192.168.0.99:5000/flannel:v0.12.0-s390x
The push refers to repository [192.168.0.99:5000/flannel]
b67de7789e55: Pushed 
4c4bfa1b47e6: Pushed 
3b7ae8a9c323: Pushed 
fbd88a276dca: Pushed 
271ca11ef489: Pushed 
1f106b41b4d6: Pushed 
v0.12.0-s390x: digest: sha256:3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6 size: 1579
[root@docker_registry ~]# docker push docker-registry.io:5000/centos:7
The push refers to repository [docker-registry.io:5000/centos]
edf3aa290fb3: Pushed 
7: digest: sha256:c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941 size: 529
[root@docker_registry ~]# 

  提示:可以看到我們上傳的兩個鏡像都完成了上傳沒有報錯,接下來我們去/var/lib/registry/這個目錄,看看是否有這兩個鏡像相關目錄?

[root@docker_registry ~]# tree /var/lib/registry/
/var/lib/registry/
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 13
            │       │   └── 13b80a37370b57f558a2e06092c39224e5d1ebac50e48df0afdeb43cf2303e60
            │       │       └── data
            │       ├── 17
            │       │   └── 176bad61a3a435da03ec603d2bd8f7a69286d92f21f447b17f21f0bc4e085bde
            │       │       └── data
            │       ├── 1b
            │       │   └── 1b56fbc8a8e10830867455c0794a70f5469c154cdc013554daf501aeda3f30fe
            │       │       └── data
            │       ├── 26
            │       │   └── 266247e2e603e1c840f97cb4d97a08b9184344e9802966cb42c93d21c407839f
            │       │       └── data
            │       ├── 3c
            │       │   └── 3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6
            │       │       └── data
            │       ├── 42
            │       │   └── 42d8e66fa893de4beb5d136b787cf182b24b7f4972c4212b9493b661ad1d7e85
            │       │       └── data
            │       ├── 52
            │       │   └── 524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc
            │       │       └── data
            │       ├── 57
            │       │   └── 57eade024bfbd48c45ef2bad996c4d6a0fa41b692247294745265af738066813
            │       │       └── data
            │       ├── 85
            │       │   └── 85ecb68de4693bb4093d923f6d1062766e4fa7cbb3bf456a2bc19dd3e6c5e6c6
            │       │       └── data
            │       ├── b5
            │       │   └── b5b4d78bc90ccd15806443fb881e35b5ddba924e2f475c1071a38a3094c3081d
            │       │       └── data
            │       └── c2
            │           └── c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941
            │               └── data
            └── repositories
                ├── centos
                │   ├── _layers
                │   │   └── sha256
                │   │       ├── 524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc
                │   │       │   └── link
                │   │       └── b5b4d78bc90ccd15806443fb881e35b5ddba924e2f475c1071a38a3094c3081d
                │   │           └── link
                │   ├── _manifests
                │   │   ├── revisions
                │   │   │   └── sha256
                │   │   │       └── c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941
                │   │   │           └── link
                │   │   └── tags
                │   │       └── 7
                │   │           ├── current
                │   │           │   └── link
                │   │           └── index
                │   │               └── sha256
                │   │                   └── c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941
                │   │                       └── link
                │   └── _uploads
                └── flannel
                    ├── _layers
                    │   └── sha256
                    │       ├── 13b80a37370b57f558a2e06092c39224e5d1ebac50e48df0afdeb43cf2303e60
                    │       │   └── link
                    │       ├── 176bad61a3a435da03ec603d2bd8f7a69286d92f21f447b17f21f0bc4e085bde
                    │       │   └── link
                    │       ├── 1b56fbc8a8e10830867455c0794a70f5469c154cdc013554daf501aeda3f30fe
                    │       │   └── link
                    │       ├── 266247e2e603e1c840f97cb4d97a08b9184344e9802966cb42c93d21c407839f
                    │       │   └── link
                    │       ├── 42d8e66fa893de4beb5d136b787cf182b24b7f4972c4212b9493b661ad1d7e85
                    │       │   └── link
                    │       ├── 57eade024bfbd48c45ef2bad996c4d6a0fa41b692247294745265af738066813
                    │       │   └── link
                    │       └── 85ecb68de4693bb4093d923f6d1062766e4fa7cbb3bf456a2bc19dd3e6c5e6c6
                    │           └── link
                    ├── _manifests
                    │   ├── revisions
                    │   │   └── sha256
                    │   │       └── 3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6
                    │   │           └── link
                    │   └── tags
                    │       └── v0.12.0-s390x
                    │           ├── current
                    │           │   └── link
                    │           └── index
                    │               └── sha256
                    │                   └── 3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6
                    │                       └── link
                    └── _uploads

65 directories, 26 files
[root@docker_registry ~]# 

  提示:可以看到對應目錄下有兩個子目錄就是以我們上傳的鏡像名稱命名的;

  示例:查看私有倉庫中存在的進行列表

[root@docker_registry ~]# curl docker-registry.io:5000/v2/_catalog
{"repositories":["centos","flannel"]}
[root@docker_registry ~]# 

  示例:下載私有倉庫中的鏡像到本地

[root@docker_node01 ~]# ip a l ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:22:36:7f brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.22/24 brd 192.168.0.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe22:367f/64 scope link 
       valid_lft forever preferred_lft forever
[root@docker_node01 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
linux1874/myimg     v0.1                e408b1c6e04f        2 weeks ago         1.22MB
wordpress           latest              c3fa1c8546fb        5 weeks ago         540MB
mysql               5.7                 f965319e89de        5 weeks ago         448MB
alpine              v3                  f70734b6a266        6 weeks ago         5.61MB
nginx               1.14-alpine         8a2fb25a19f5        14 months ago       16MB
httpd               2.4.37-alpine       dfd436f9a5d8        17 months ago       91.8MB
[root@docker_node01 ~]# docker pull 192.168.0.99:5000/flannel:v0.12.0-s390x
v0.12.0-s390x: Pulling from flannel
176bad61a3a4: Pull complete 
13b80a37370b: Pull complete 
42d8e66fa893: Pull complete 
266247e2e603: Pull complete 
1b56fbc8a8e1: Pull complete 
85ecb68de469: Pull complete 
Digest: sha256:3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6
Status: Downloaded newer image for 192.168.0.99:5000/flannel:v0.12.0-s390x
192.168.0.99:5000/flannel:v0.12.0-s390x
[root@docker_node01 ~]# docker images
REPOSITORY                  TAG                 IMAGE ID            CREATED             SIZE
linux1874/myimg             v0.1                e408b1c6e04f        2 weeks ago         1.22MB
wordpress                   latest              c3fa1c8546fb        5 weeks ago         540MB
mysql                       5.7                 f965319e89de        5 weeks ago         448MB
alpine                      v3                  f70734b6a266        6 weeks ago         5.61MB
192.168.0.99:5000/flannel   v0.12.0-s390x       57eade024bfb        2 months ago        56.9MB
nginx                       1.14-alpine         8a2fb25a19f5        14 months ago       16MB
httpd                       2.4.37-alpine       dfd436f9a5d8        17 months ago       91.8MB
[root@docker_node01 ~]# 

  提示:下載私有倉庫中的鏡像,默認情況docker也是不支持直接訪問http協議的倉庫,需要我們手動去配置insecure-registries,然後重啟docker才可以;

  示例:刪除私有倉庫中的鏡像

  1、獲取對應鏡像的sha256的值 curl –header “Accept:application/vnd.docker.distribution.manifest.v2+json” -I -X GET http://<registry addr>/v2/<image name>/manifests/<image tag>

  2、刪除對應鏡像版本元數據 curl -I -X DELETE http://<registry addr>/v2/<image name>/manifests/<image digest>

  提示:如果響應405方法不被允許;我們需要修改私有倉庫的配置文件,將其配置為允許刪除;如下

[root@docker_registry ~]# cat /etc/docker-distribution/registry/config.yml
version: 0.1
log:
  fields:
    service: registry
storage:
    delete:
        enabled: true
    cache:
        layerinfo: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
http:
    addr: :5000
[root@docker_registry ~]# systemctl restart docker-distribution           
[root@docker_registry ~]# curl -IX DELETE http://docker-registry.io:5000/v2/centos/manifests/sha256:c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941
HTTP/1.1 202 Accepted
Docker-Distribution-Api-Version: registry/2.0
Date: Sat, 06 Jun 2020 19:55:52 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

[root@docker_registry ~]#

  提示:degest值包含”sha256:”

  3、垃圾回收清理

[root@docker_registry ~]# registry garbage-collect /etc/docker-distribution/registry/config.yml 
centos
flannel
flannel: marking manifest sha256:3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6 
flannel: marking blob sha256:57eade024bfbd48c45ef2bad996c4d6a0fa41b692247294745265af738066813
flannel: marking blob sha256:176bad61a3a435da03ec603d2bd8f7a69286d92f21f447b17f21f0bc4e085bde
flannel: marking blob sha256:13b80a37370b57f558a2e06092c39224e5d1ebac50e48df0afdeb43cf2303e60
flannel: marking blob sha256:42d8e66fa893de4beb5d136b787cf182b24b7f4972c4212b9493b661ad1d7e85
flannel: marking blob sha256:266247e2e603e1c840f97cb4d97a08b9184344e9802966cb42c93d21c407839f
flannel: marking blob sha256:1b56fbc8a8e10830867455c0794a70f5469c154cdc013554daf501aeda3f30fe
flannel: marking blob sha256:85ecb68de4693bb4093d923f6d1062766e4fa7cbb3bf456a2bc19dd3e6c5e6c6
myweb
myweb: marking manifest sha256:aaf04cf567a776e36eb3b0bafaec17ed8d9e0a743bdb897dca13f251250ae493 
myweb: marking blob sha256:4f406abeaab7f848178867409142090d1a551b22b968be6a6dae733c8403738e
myweb: marking blob sha256:524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc
myweb: marking blob sha256:c941076f9075280c41b502283f37ab8bafef3a66f4a7ba299838dce07641a48d
test
test: marking manifest sha256:5ecad23ab8a52e55f93968f708d325261032dd613287aec92e7cf8ddd6426635 
test: marking blob sha256:370e3a843c3cb12700301e3f87f929939146cd8b676260bedcd83aaa7fcc2939
test: marking blob sha256:524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc
test: marking manifest sha256:da8b53210bf1f4dc4873bbd5589abad616663cda45205ae3a4fffb0729d2730d 
test: marking blob sha256:461f6ceabc885e2e90b5f9ee82aefc9a30a39510c40e7cd8fb7436a4d340fe1d
test: marking blob sha256:524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc
test: marking blob sha256:035e026f1d6b0acba3413ba616dcbabf75d20e945778c52716e601255452b7b7

17 blobs marked, 2 blobs eligible for deletion
blob eligible for deletion: sha256:b5b4d78bc90ccd15806443fb881e35b5ddba924e2f475c1071a38a3094c3081d
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/b5/b5b4d78bc90ccd15806443fb881e35b5ddba924e2f475c1071a38a3094c3081d  go.version=go1.9.4 instance.id=b3029d7f-99e8-4941-8c87-989514b584ea
blob eligible for deletion: sha256:c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/c2/c2f1d5a9c0a81350fa0ad7e1eee99e379d75fe53823d44b5469eb2eb6092c941  go.version=go1.9.4 instance.id=b3029d7f-99e8-4941-8c87-989514b584ea
[root@docker_registry ~]# 

  測試:下載docker-registry.io:5000/centos:7 看看是否還能下載?

[root@docker_node01 ~]# docker pull 192.168.0.99:5000/centos:7
Error response from daemon: manifest for 192.168.0.99:5000/centos:7 not found: manifest unknown: manifest unknown
[root@docker_node01 ~]# 

  提示:以上提示告訴我們沒有對應鏡像的元數據信息;說明我們私有倉庫沒有對應鏡像;以上方法適合精準刪除某個鏡像的某個版本,如果是刪除一個倉庫,直接刪除 /var/lib/registry/docker/registry/v2/repositories/下對應倉庫的目錄,然後在用registry命令做垃圾回收;如下

[root@docker_registry ~]# ll /var/lib/registry/docker/registry/v2/repositories/
total 0
drwxr-xr-x 5 root root 55 Jun  6 14:16 centos
drwxr-xr-x 5 root root 55 Jun  6 14:15 flannel
drwxr-xr-x 5 root root 55 Jun  6 15:25 myweb
drwxr-xr-x 5 root root 55 Jun  6 15:24 test
[root@docker_registry ~]# rm -rf /var/lib/registry/docker/registry/v2/repositories/test
[root@docker_registry ~]# rm -rf /var/lib/registry/docker/registry/v2/repositories/myweb
[root@docker_registry ~]# ll /var/lib/registry/docker/registry/v2/repositories/
total 0
drwxr-xr-x 5 root root 55 Jun  6 14:16 centos
drwxr-xr-x 5 root root 55 Jun  6 14:15 flannel
[root@docker_registry ~]# registry garbage-collect /etc/docker-distribution/registry/config.yml 
centos
flannel
flannel: marking manifest sha256:3ce5b8d40451787e1166bf6b207c7834c13f7a0712b46ddbfb591d8b5906bfa6 
flannel: marking blob sha256:57eade024bfbd48c45ef2bad996c4d6a0fa41b692247294745265af738066813
flannel: marking blob sha256:176bad61a3a435da03ec603d2bd8f7a69286d92f21f447b17f21f0bc4e085bde
flannel: marking blob sha256:13b80a37370b57f558a2e06092c39224e5d1ebac50e48df0afdeb43cf2303e60
flannel: marking blob sha256:42d8e66fa893de4beb5d136b787cf182b24b7f4972c4212b9493b661ad1d7e85
flannel: marking blob sha256:266247e2e603e1c840f97cb4d97a08b9184344e9802966cb42c93d21c407839f
flannel: marking blob sha256:1b56fbc8a8e10830867455c0794a70f5469c154cdc013554daf501aeda3f30fe
flannel: marking blob sha256:85ecb68de4693bb4093d923f6d1062766e4fa7cbb3bf456a2bc19dd3e6c5e6c6

8 blobs marked, 9 blobs eligible for deletion
blob eligible for deletion: sha256:370e3a843c3cb12700301e3f87f929939146cd8b676260bedcd83aaa7fcc2939
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/37/370e3a843c3cb12700301e3f87f929939146cd8b676260bedcd83aaa7fcc2939  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/52/524b0c1e57f8ee5fee01a1decba2f301c324a6513ca3551021264e3aa7341ebc  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:5ecad23ab8a52e55f93968f708d325261032dd613287aec92e7cf8ddd6426635
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/5e/5ecad23ab8a52e55f93968f708d325261032dd613287aec92e7cf8ddd6426635  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:aaf04cf567a776e36eb3b0bafaec17ed8d9e0a743bdb897dca13f251250ae493
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/aa/aaf04cf567a776e36eb3b0bafaec17ed8d9e0a743bdb897dca13f251250ae493  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:035e026f1d6b0acba3413ba616dcbabf75d20e945778c52716e601255452b7b7
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/03/035e026f1d6b0acba3413ba616dcbabf75d20e945778c52716e601255452b7b7  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:461f6ceabc885e2e90b5f9ee82aefc9a30a39510c40e7cd8fb7436a4d340fe1d
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/46/461f6ceabc885e2e90b5f9ee82aefc9a30a39510c40e7cd8fb7436a4d340fe1d  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:4f406abeaab7f848178867409142090d1a551b22b968be6a6dae733c8403738e
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/4f/4f406abeaab7f848178867409142090d1a551b22b968be6a6dae733c8403738e  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:c941076f9075280c41b502283f37ab8bafef3a66f4a7ba299838dce07641a48d
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/c9/c941076f9075280c41b502283f37ab8bafef3a66f4a7ba299838dce07641a48d  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
blob eligible for deletion: sha256:da8b53210bf1f4dc4873bbd5589abad616663cda45205ae3a4fffb0729d2730d
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/da/da8b53210bf1f4dc4873bbd5589abad616663cda45205ae3a4fffb0729d2730d  go.version=go1.9.4 instance.id=1a15f1e7-194f-4a82-b79d-9f437d975f6e
[root@docker_registry ~]# 

  提示:這種方式比較粗暴簡單,通常是一個倉庫里只有一個版本鏡像可以使用這種方式刪除,如果一個倉庫有多個版本,那麼還是建議使用第一種方式;

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※回頭車貨運收費標準

※推薦評價好的iphone維修中心

※超省錢租車方案

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

※推薦台中搬家公司優質服務,可到府估價

用雲開發Cloudbase,實現小程序多圖片內容安全監測

前言

相比於文本的安全檢測,圖片的安全檢測要稍微略複雜一些,當您讀完本篇,將get到

  • 圖片安全檢測的應用場景
  • 解決圖片的安全校驗的方式
  • 使用雲調用方式對圖片進行檢測
  • 如何對上傳圖片大小進行限制
  • 如何解決多圖上傳覆蓋問題

示例效果

當用戶上傳敏感違規圖片時,禁止用戶上傳發布,並且做出相對應的用戶友好提示

應用場景

通常,在校驗一張圖片是否含有違法違規內容相比於文本安全的校驗,同樣重要,有如下應用

  • 圖片智能鑒黃:涉及拍照的工具類應用(如美拍,識圖類應用)用戶拍照上傳檢測;電商類商品上架圖片檢測;媒體類用戶文章里的圖片檢測等
  • 敏感人臉識別:用戶頭像;媒體類用戶文章里的圖片檢測;社交類用戶上傳的圖片檢測等,凡是有用戶自發生產內容的都應當提前做檢測

解決圖片的安全手段

在小程序開發中,提供了兩種方式

  • HTTPS調用
  • 雲調用

HTTPS 調用的請求接口地止

https://api.weixin.qq.com/wxa/img_sec_check?access_token=ACCESS_TOKEN

檢測圖片審核,根據官方文檔得知,需要兩個必傳的參數:分別是:access_token(接口調用憑證),media(要檢測的圖片文件)

對於HTTPS調用方式,願意折騰的小夥伴可以參考文本內容安全檢測(上篇)的處理方式,處理大同小異,本篇主要以雲開發的雲調用為主

功能實現:小程序端邏輯

對於wxml與wxss,大家可以自行任意修改,本文重點在於圖片安全的校驗

<view class="image-list">
<!-- 显示圖片 -->
   <block wx:for="{{images}}" wx:key="*this"><view class="image-wrap">
       <image class="image" src="{{item}}" mode="aspectFill" bind:tap="onPreviewImage" data-imgsrc="{{item}}"></image><i class="iconfont icon-shanchu" bind:tap="onDelImage" data-index="{{index}}"></i></view>
   </block>
   <!-- 選擇圖片 -->
   <view class="image-wrap selectphoto" hidden="{{!selectPhoto}}" bind:tap="onChooseImage"><i class="iconfont icon-add"></i></view>
   </view>
   <view class="footer"><button class="send-btn"  bind:tap="send">發布</button>
   </view>

對應的wxss代碼

.footer {
  display: flex;
  align-items: center;
  width: 100%;
  box-sizing: border-box;
  background: #34bfa3;
}

.send-btn {
  width: 100%;
  color: #fff;
  font-size: 32rpx;
  background: #34bfa3;
}

button {
  border-radius: 0rpx;
}

button::after {
  border-radius: 0rpx !important;
}

/* 圖片樣式 */
.image-list {
  display: flex;
  flex-wrap: wrap;
  margin-top: 20rpx;
}

.image-wrap {
  width: 220rpx;
  height: 220rpx;
  margin-right: 10rpx;
  margin-bottom: 10rpx;
  position: relative;
  overflow: hidden;
  text-align: center;
}

.image {
  width: 100%;
  height: 100%;
}

.icon-shanchu {
  position: absolute;
  top: 0;
  right: 0;
  width: 40rpx;
  height: 40rpx;
  background-color: #000;
  opacity: 0.4;
  color: #fff;
  text-align: center;
  line-height: 40rpx;
  font-size: 38rpx;
  font-weight: bolder;
}

.selectphoto {
  border: 2rpx dashed #cbd1d7;
  position: relative;
}

.icon-add {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #cbd1d7;
  font-size: 60rpx;
}

最終呈現的UI,由於只是用於圖片檢測演示,UI方面可忽略,如下所示

對應的JS代碼

/*
* 涉及到的API:wx.chooseImage  從本地相冊選擇圖片或使用相機拍照
*(https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html)


*
*
*/// 最大上傳圖片數量
const MAX_IMG_NUM = 9;

const db = wx.cloud.database(); // 初始化雲數據庫
Page({

  /**
   * 頁面的初始數據
   */
  data: {
    images: [],  // 把上傳的圖片存放在一個數組對象裏面
    selectPhoto: true, // 添加+icon元素是否显示
  },

  /**
   * 生命周期函數--監聽頁面加載
   */
  onLoad: function (options) {

  },

  // 選擇圖片
  onChooseImage() {
    // 還能再選幾張圖片,初始值設置最大的數量-當前的圖片的長度
    let max = MAX_IMG_NUM - this.data.images.length; 
    wx.chooseImage({
      count: max,               // count表示最多可以選擇的圖片張數
      sizeType: ['original', 'compressed'], //  所選的圖片的尺寸
      sourceType: ['album', 'camera'],  // 選擇圖片的來源
      success: (res) => {                     // 接口調用成功的回調函數console.log(res)
        this.setData({                       // tempFilePath可以作為img標籤的src屬性显示圖片,下面是將后添加的圖片與之前的圖片給追加起來
          images: this.data.images.concat(res.tempFilePaths)
        })
        // 還能再選幾張圖片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true  // 當超過9張時,加號隱藏
        })
      },
    })
  },

  // 點擊右上方刪除圖標,刪除圖片操作
  onDelImage(event) {
    const index = event.target.dataset.index;
    // 點擊刪除當前圖片,用splice方法,刪除一張,從數組中移除一個                                                       
    this.data.images.splice(index, 1)
    this.setData({
      images: this.data.images
    })
    // 當添加的圖片達到設置最大的數量時,添加按鈕隱藏,不讓新添加圖片
    if (this.data.images.length == MAX_IMG_NUM - 1) {
      this.setData({
        selectPhoto: true,
      })
    }
  },
})

最終實現的前端UI效果如下所是:

您現在看到的效果,沒有任何雲函數代碼,只是前端的純靜態展示,對於一些涉嫌敏感圖片,是有必要進行做過濾處理的

功能實現:雲函數側邏輯

在cloudfunctions目錄文件夾下創建雲函數imgSecCheck

並在該目錄下創建config.json,配置參數如下所示

{
  "permissions": {
    "openapi": [
      "security.imgSecCheck"
    ]
  }
}

配置完后,在主入口index.js中,如下所示,通過security.imgSecCheck接口,並傳入media對象

// 雲函數入口文件
const cloud = require('wx-server-sdk');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

// 雲函數入口函數
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  try {
    const result = await cloud.openapi.security.imgSecCheck({
      media: {
        contentType: 'image/png',
        value: Buffer.from(event.img)   // 這裏必須要將小程序端傳過來的進行Buffer轉化,否則就會報錯,接口異常
      }
      
    })

    if (result && result.errCode.toString() === '87014') {
      return { code: 500, msg: '內容含有違法違規內容', data: result }
    } else {
      return { code: 200, msg: '內容ok', data: result }
    }
  } catch (err) {
    // 錯誤處理
    if (err.errCode.toString() === '87014') {
      return { code: 500, msg: '內容含有違法違規內容', data: err }
    }
    return { code: 502, msg: '調用imgSecCheck接口異常', data: err }
  }
}

您會發現在雲函數端,就這麼幾行代碼,就完成了圖片安全校驗

而在小程序端,代碼如下所示

// miniprogram/pages/imgSecCheck/imgSecCheck.js
// 最大上傳圖片數量
const MAX_IMG_NUM = 9;

const db = wx.cloud.database()
Page({

  /**
   * 頁面的初始數據
   */
  data: {
    images: [],
    selectPhoto: true, // 添加圖片元素是否显示
  },

  /**
   * 生命周期函數--監聽頁面加載
   */
  onLoad: function (options) {

  },
  // 選擇圖片
  onChooseImage() {
    // const that = this;  // 如果下面用了箭頭函數,那麼這行代碼是不需要的,直接用this就可以了的// 還能再選幾張圖片,初始值設置最大的數量-當前的圖片的長度
    let max = MAX_IMG_NUM - this.data.images.length; 
    wx.chooseImage({
      count: max,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: (res) => {  // 這裏若不是箭頭函數,那麼下面的this.setData的this要換成that上面的臨時變量,作用域的問題,不清楚的,可以看下this指向相關的知識
       console.log(res)
       // tempFilePath可以作為img標籤的src屬性显示圖片
        const  tempFiles = res.tempFiles;
        this.setData({
          images: this.data.images.concat(res.tempFilePaths)
        })
        // 在選擇圖片時,對本地臨時存儲的圖片,這個時候,進行圖片的校驗,當然你放在最後點擊發布時,進行校驗也是可以的,只不過是一個前置校驗和後置校驗的問題,我個人傾向於在選擇圖片時就進行校驗的,選擇一些照片時,就應該在選擇時階段做安全判斷的, 小程序端請求雲函數方式// 圖片轉化buffer后,調用雲函數
        console.log(tempFiles);
        tempFiles.forEach(items => {
          console.log(items);
          // 圖片轉化buffer后,調用雲函數
          wx.getFileSystemManager().readFile({
            filePath: items.path,
            success: res => {
                  console.log(res);
                   wx.cloud.callFunction({  // 小程序端請求imgSecCheck雲函數,並傳遞img參數進行檢驗
                    name: 'imgSecCheck',
                    data: {
                      img: res.data
                    }
            })
            .then(res => {
               console.log(res);
               let { errCode } = res.result.data;
               switch(errCode) {
                 case 87014:
                   this.setData({
                      resultText: '內容含有違法違規內容'
                   })
                   break;
                 case 0:
                   this.setData({
                     resultText: '內容OK'
                   })
                   break;
                 default:
                   break;
               }
 
            })
            .catch(err => {
               console.error(err);
            })
            },
            fail: err => {
              console.error(err);
            }
          })
        })
        
            
        // 還能再選幾張圖片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true  // 當超過9張時,加號隱藏
        })
      },
    })
  },

  // 刪除圖片
  onDelImage(event) {
    const index =  event.target.dataset.index;
    // 點擊刪除當前圖片,用splice方法,刪除一張,從數組中移除一個
    this.data.images.splice(index, 1);
    this.setData({
      images: this.data.images
    })
    // 當添加的圖片達到設置最大的數量時,添加按鈕隱藏,不讓新添加圖片
    if (this.data.images.length == MAX_IMG_NUM - 1) {
      this.setData({
        selectPhoto: true,
      })
    }
  },
})

示例效果如下所示:

至此,關於圖片安全檢測就已經完成了,您只需要根據檢測的結果,做一些友好的用戶提示,或者做一些自己的業務邏輯判斷即可

常見問題

如何對上傳的圖片大小進行限制

有時候,您需要對用戶上傳圖片的大小進行限制,限制用戶任意上傳超大圖片,那怎麼處理呢,在微信小程序裏面,主要藉助的是wx.chooseImage這個接口成功返回后臨時路徑的res.tempFiles中的size大小判斷即可進行處理

具體實例代碼如下所示

// 選擇圖片
  onChooseImage() {
    // 還能再選幾張圖片,初始值設置最大的數量-當前的圖片的長度
    let max = MAX_IMG_NUM - this.data.images.length; 
    wx.chooseImage({
      count: max,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: (res) => {
        console.log(res)
        const  tempFiles = res.tempFiles;
        this.setData({
          images: this.data.images.concat(res.tempFilePaths)  // tempFilePath可以作為img標籤的src屬性显示圖片
        })
        // 在選擇圖片時,對本地臨時存儲的圖片,這個時候,進行圖片的校驗,當然你放在最後點擊發布時,進行校驗也是可以的,只不過是一個前置校驗和後置校驗的問題,我個人傾向於在選擇圖片時就進行校驗的,選擇一些照片時,就應該在選擇時階段做安全判斷的, 小程序端請求雲函數方式// 圖片轉化buffer后,調用雲函數
        console.log(tempFiles);
        tempFiles.forEach(items => {
          if (items && items.size > 1 * (1024 * 1024)) {  // 限製圖片的大小
            wx.showToast({
              icon: 'none',
              title: '上傳的圖片超過1M,禁止用戶上傳',
              duration: 4000
            })
            // 超過1M的圖片,禁止用戶上傳
          }
          console.log(items);
          // 圖片轉化buffer后,調用雲函數
          wx.getFileSystemManager().readFile({
            filePath: items.path,
            success: res => {
                  console.log(res);
                   wx.cloud.callFunction({   // 請求調用雲函數imgSecCheck
                    name: 'imgSecCheck',
                    data: {
                      img: res.data
                    }
            })
            .then(res => {
               console.log(res);
               let { errCode } = res.result.data;
               switch(errCode) {
                 case 87014:
                   this.setData({
                      resultText: '內容含有違法違規內容'
                   })
                   break;
                 case 0:
                   this.setData({
                     resultText: '內容OK'
                   })
                   break;
                 default:
                   break;
               }
            })
            .catch(err => {
               console.error(err);
            })
            },
            fail: err => {
              console.error(err);
            }
          })
        })
       
        // 還能再選幾張圖片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true  // 當超過9張時,加號隱藏
        })
      },
    })
  },

注意: 使用微信官方的圖片內容安全接口進行校驗,限製圖片大小限制:1M,否則的話就會報錯

也就是說,對於超過1M大小的違規圖片,微信官方提供的這個圖片安全接口是無法進行校驗的

這個根據自己的業務而定,在小程序端對用戶上傳圖片的大小進行限制如果您覺得微信官方提供的圖片安全接口滿足不了自己的業務需求,那麼可以選擇一些其他的圖片內容安全校驗的接口的

這個圖片安全校驗是非常有必要的,用戶一旦上傳非法圖片,一旦通過網絡進行傳播,產生了社會影響,平台是有責任的,這種前車之鑒是有的

如何解決多圖上傳覆蓋的問題

對於上傳圖片來說,這個wx.cloud.uploadFileAPI接口只能上傳一張圖片,但是很多時候,是需要上傳多張圖片到雲存儲當中的,當點擊發布的時候,我們是希望將多張圖片都上傳到雲存儲當中去的

這個API雖然只能每次上傳一張,但您可以循環遍歷多張圖片,然後一張一張的上傳的

在cloudPath上傳文件的參數當中,它的值:需要注意:文件的名稱

那如何保證上傳的圖片不被覆蓋,文件不重名的情況下就不會被覆蓋

而在選擇圖片的時候,不應該上傳,因為用戶可能有刪除等操作,如果直接上傳的話會造成資源的浪費

而應該在點發布按鈕的時候,才執行上傳操作,文件不重名覆蓋的示例代碼如下所示

      let promiseArr = []
      let fileIds = []      // 將圖片的fileId存放到一個數組中
      let imgLength = this.data.images.length;
      // 圖片上傳
      for (let i = 0; i < imgLength; i++) {
        let p = new Promise((resolve, reject) => {
        let item = this.data.images[i]
          // 文件擴展名
          let suffix = /\.\w+$/.exec(item)[0]; // 取文件后拓展名
          wx.cloud.uploadFile({      // 利用官方提供的上傳接口
            cloudPath: 'blog/' + Date.now() + '-' + Math.random() * 1000000 + suffix,  // 雲存儲路徑,您也可以使用es6中的模板字符串進行拼接的
            filePath: item,   // 要上傳文件資源的路徑
            success: (res) => {
              console.log(res);
              console.log(res.fileID)
              fileIds = fileIds.concat(res.fileID)       // 將新上傳的與之前上傳的給拼接起來
              resolve()
            },
            fail: (err) => {
              console.error(err)
              reject()
            }
          })
        })
        promiseArr.push(p)
      }
      // 存入到雲數據庫,其中這個Promise.all(),等待裏面所有的任務都執行之後,在去執行後面的任務,也就是等待上傳所有的圖片上傳完后,才能把相對應的數據存到數據庫當中,具體與promise相關問題,可自行查漏
      Promise.all(promiseArr).then((res) => {
          db.collection('blog').add({ // 查找blog集合,將img,時間等數據添加到這個集合當中
            data: {
              img: fileIds,
              createTime: db.serverDate(), // 服務端的時間
            }
          }).then((res) => {
            console.log(res);
            this._hideToastTip();
            this._successTip();
          })
        })
        .catch((err) => {
          // 發布失敗console.error(err);
        })

上面通過利用當前時間+隨機數的方式進行了一個區分,規避了上傳文件同名的問題

因為這個上傳接口,一次性只能上傳一張圖片,所以需要循環遍歷圖片,然後一張張的上傳

一個是上傳到雲存儲中,另一個是添加到雲數據庫集合當中,要分別注意下這兩個操作,雲數據庫中的圖片是從雲存儲中拿到的,然後再添加到雲數據庫當中去的

示例效果如下所示:

將上傳的圖片存儲到雲數據庫中

注意:添加數據到雲數據庫中,需要手動創建集合,不然是無法上傳不到雲數據庫當中的,會報錯

至此,關於敏感圖片的檢測,以及多圖片的上傳到這裏就已經完成了

如下是完整的小程序端邏輯示例代碼

// miniprogram/pages/imgSecCheck/imgSecCheck.js
// 最大上傳圖片數量
const MAX_IMG_NUM = 9;
const db = wx.cloud.database()
Page({

  /**
   * 頁面的初始數據
   */
  data: {
    images: [],
    selectPhoto: true, // 添加圖片元素是否显示
  },

  /**
   * 生命周期函數--監聽頁面加載
   */
  onLoad: function (options) {

  },

  // 選擇圖片
  onChooseImage() {
    // 還能再選幾張圖片,初始值設置最大的數量-當前的圖片的長度
    let max = MAX_IMG_NUM - this.data.images.length;
    wx.chooseImage({
      count: max,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: (res) => {
        console.log(res)
        const tempFiles = res.tempFiles;
        this.setData({
          images: this.data.images.concat(res.tempFilePaths) // tempFilePath可以作為img標籤的src屬性显示圖片
        })
        // 在選擇圖片時,對本地臨時存儲的圖片,這個時候,進行圖片的校驗,當然你放在最後點擊發布時,進行校驗也是可以的,只不過是一個前置校驗和後置校驗的問題,我個人傾向於在選擇圖片時就進行校驗的,選擇一些照片時,就應該在選擇時階段做安全判斷的, 小程序端請求雲函數方式
        // 圖片轉化buffer后,調用雲函數
        console.log(tempFiles);
        tempFiles.forEach(items => {
          if (items && items.size > 1 * (1024 * 1024)) {
            wx.showToast({
              icon: 'none',
              title: '上傳的圖片超過1M,禁止用戶上傳',
              duration: 4000
            })
            // 超過1M的圖片,禁止上傳
          }
          console.log(items);
          // 圖片轉化buffer后,調用雲函數
          wx.getFileSystemManager().readFile({
            filePath: items.path,
            success: res => {
              console.log(res);
              this._checkImgSafe(res.data); // 檢測圖片安全校驗
            },
            fail: err => {
              console.error(err);
            }
          })
        })


        // 還能再選幾張圖片
        max = MAX_IMG_NUM - this.data.images.length
        this.setData({
          selectPhoto: max <= 0 ? false : true // 當超過9張時,加號隱藏
        })
      },
    })
  },

  // 刪除圖片
  onDelImage(event) {
    const index = event.target.dataset.index;
    // 點擊刪除當前圖片,用splice方法,刪除一張,從數組中移除一個
    this.data.images.splice(index, 1);
    this.setData({
      images: this.data.images
    })
    // 當添加的圖片達到設置最大的數量時,添加按鈕隱藏,不讓新添加圖片
    if (this.data.images.length == MAX_IMG_NUM - 1) {
      this.setData({
        selectPhoto: true,
      })
    }
  },

  // 點擊發布按鈕,將圖片上傳到雲數據庫當中
  send() {
    const images = this.data.images.length;
    if (images) {
      this._showToastTip();
      let promiseArr = []
      let fileIds = []
      let imgLength = this.data.images.length;
      // 圖片上傳
      for (let i = 0; i < imgLength; i++) {
        let p = new Promise((resolve, reject) => {
          let item = this.data.images[i]
          // 文件擴展名
          let suffix = /\.\w+$/.exec(item)[0]; // 取文件后拓展名
          wx.cloud.uploadFile({   // 上傳圖片至雲存儲,循環遍歷,一張張的上傳
            cloudPath: 'blog/' + Date.now() + '-' + Math.random() * 1000000 + suffix,
            filePath: item,
            success: (res) => {
              console.log(res);
              console.log(res.fileID)
              fileIds = fileIds.concat(res.fileID)
              resolve()

            },
            fail: (err) => {
              console.error(err)
              reject()
            }
          })
        })
        promiseArr.push(p)
      }
      // 存入到雲數據庫
      Promise.all(promiseArr).then((res) => {
          db.collection('blog').add({ // 查找blog集合,將數據添加到這個集合當中
            data: {
              img: fileIds,
              createTime: db.serverDate(), // 服務端的時間
            }
          }).then((res) => {
            console.log(res);
            this._hideToastTip();
            this._successTip();
          })
        })
        .catch((err) => {
          // 發布失敗
          console.error(err);
        })
    } else {
      wx.showToast({
        icon: 'none',
        title: '沒有選擇任何圖片,發布不了',
      })
    }

  },

  // 校驗圖片的安全
  _checkImgSafe(data) {
    wx.cloud.callFunction({
        name: 'imgSecCheck',
        data: {
          img: data
        }
      })
      .then(res => {
        console.log(res);
        let {
          errCode
        } = res.result.data;
        switch (errCode) {
          case 87014:
            this.setData({
              resultText: '內容含有違法違規內容'
            })
            break;
          case 0:
            this.setData({
              resultText: '內容OK'
            })
            break;
          default:
            break;
        }
      })
      .catch(err => {
        console.error(err);
      })
  },

  _showToastTip() {
    wx.showToast({
      icon: 'none',
      title: '發布中...',
    })
  },

  _hideToastTip() {
    wx.hideLoading();
  },

  _successTip() {
    wx.showToast({
      icon: 'none',
      title: '發布成功',
    })
  },
})

完整的示例wxml,如下所示

<view class="image-list">
<!-- 显示圖片 -->
<block wx:for="{{images}}" wx:key="*this">
     <view class="image-wrap"><image class="image" src="{{item}}" mode="aspectFill" bind:tap="onPreviewImage" data-imgsrc="{{item}}"></image><i class="iconfont icon-shanchu" bind:tap="onDelImage" data-index="{{index}}"></i>
     </view>
</block>
<!-- 選擇圖片 -->
<view class="image-wrap selectphoto" hidden="{{!selectPhoto}}" bind:tap="onChooseImage"><i class="iconfont icon-add"></i></view>
</view>
<view class="footer">
   <button class="send-btn"  bind:tap="send">發布</button>
</view>
<view>
    檢測結果显示: {{ resultText }}
</view>

您可以根據自己的業務邏輯需要,一旦檢測到圖片違規時,禁用按鈕狀態,或者給一些用戶提示,都是可以的,在發布之前或者點擊發布時,進行圖片內容安全的校驗都可以,一旦發現圖片有違規時,就不讓繼續後面的操作的

結語

本文主要通過藉助官方提供的圖片security.imgSecCheck

接口,實現了對圖片安全的校驗,實現起來,是相當的方便的,對於基礎性的校驗,利用官方提供的這個接口,已經夠用了的,但是如果想要更加嚴格的檢測,可以引入一些第三方的內容安全強強校驗,確保內容的安全

實現了如何對上傳的圖片大小進行限制,以及解決同名圖片上傳覆蓋的問題

如果大家對文本內容安全校驗以及圖片安全校驗仍然有什麼問題,可以在下方留言,一起探討。

雲開發公眾號:騰訊云云開發

雲開發技術文檔:https://cloudbase.net

雲開發技術交流加Q群:601134960

更多精彩
掃描二維碼了解更多

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※回頭車貨運收費標準

※產品缺大量曝光嗎?你需要的是一流包裝設計!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※推薦評價好的iphone維修中心

※教你寫出一流的銷售文案?

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!