XieJava's blog

记录最好的自己


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

vue3+vite+axios+mock从接口获取模拟数据实战

发表于 2024-08-24 | 更新于: 2025-04-08 | 分类于 技术 | | 阅读次数:
字数统计: 1.6k | 阅读时长 ≈ 7

在用Vue.js开发前端应用时通常要与后端服务进行交互,例如通过API接口获取数据,在后端服务接口还没有具备之前,可以通过mock(模拟)数据来进行开发。使用mock数据可以让前端开发人员独立于后端开发人员工作,加快开发速度。在没有真实数据的情况下,mock数据可以帮助开发者更快地看到UI的呈现效果和交互逻辑。

本文通过vue3+vite+axios+mock来介绍如何实现Vue.js的前端应用从接口获取模拟数据。

一、安装相关组件

1
2
npm install axios -S
npm install mockjs vite-plugin-mock -D

其中axios 是一个基于 Promise 非常强大且灵活的 HTTP 客户端,适用于 Vue.js 应用程序中的数据获取和后端交互。它可以简化 HTTP 请求的处理,并提供丰富的功能来满足不同的需求。我们用axios来实现与接口服务的http请求。

Mock.js 是一个用于生成随机数据的 JavaScript 库,它主要用于前端开发过程中模拟后端接口数据。Mock.js 提供了一套简洁易用的 API,可以帮助开发者快速生成符合特定规则的假数据,从而在没有后端支持的情况下进行前端开发和测试。

vite-plugin-mock 是一个专为 Vite 设计的插件,用于在 Vite 项目中模拟数据。它简化了使用 Mock.js 的过程,让开发者能够更加方便地管理模拟数据。

简单来说,就是mock.js提供mock数据,通过vite-plugin-mock,将管理mock发布成服务,通过axios通过http请求接口的方式获取mock数据。

安装相关组件后,在package.json中看到相关的组件信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package.json
{
"name": "mocktest",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"test": "vite --mode test",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.7.5",
"vue": "^3.4.29"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.5",
"mockjs": "^1.1.0",
"vite": "^5.3.1",
"vite-plugin-mock": "^3.0.2"
}
}

二、在vite.config.js中配置vite-plugin-mock插件

● viteMockServe的相关配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteMockServe } from 'vite-plugin-mock'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
// mock 数据的 dev环境
viteMockServe({
// supportTs: true, // 是否开启支持ts
mockPath: 'mock', // 设置mockPath为根目录下的mock目录
localEnabled: true, // 设置是否监视mockPath对应的文件夹内文件中的更改
prodEnabled: false, // 设置是否启用生产环境的mock服务
watchFiles: true, // 是否监视文件更改
logger: true //是否在控制台显示请求日志
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
}
})

在viteMockServe中指定了mockPath为mock也就是根目录下的mock目录,在该目录下的mock服务都会被发布成mock服务。

三、实现mock服务

在根目录下新建mock目录在mock目录下新建mock文件实现mock服务,如app.js、user.js

mock目录

app.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
export default [{
url: '/mock/api/getApiInfo',
method: 'get',
response: () => {
return {
code: 200,
title: 'mock api test.'
}
}
},
{
url: '/api/category',
type: 'get',
response: () => {
return {
code: 200,
data: [
{
id: 1,
title: 'JAVA',
href: '/category/java'
},
{
id: 2,
title: 'SpringBoot',
href: '/category/SpringBoot',
},
{
id: 3,
title: 'MySql',
href: '/category/MySql'
},
{
id: 4,
title: '随笔',
href: '/category/live'
}
]
}
}
}
]

在app.js中我们并没有用mock生产数据,只是实现了mock服务放到了mock文件目录通过viteMockServe发布出来,后面可以通过axios调用获取。
user.js代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import Mock from 'mockjs';

// 通过Mock生成模拟数据
const userdata = Mock.mock({
'list|10': [
{
'id|+1': 1,
'name': '@cname',
'age|18-60': 1,
'email': '@email',
},
],
});

export default [
{
url: '/mock/api/getUserInfo',
method: 'get',
response: () => {
return {
code: 200,
data: userdata
}
}
},
]

在user.js中,我们通过Mock生成模拟的用户列表数据

四、调用api接口请求mock数据

方法一、直接使用axios 请求mock 数据

1
import axios from 'axios'

在方法中通过axios.get()方法直接获取请求数据

1
2
3
4
5
6
7
async getData() {
await axios.get('/mock/api/getApiInfo').then(res =>{
console.log(res.data)
this.msg = res.data.title
}
)
},

方法二、对axios进行封装统一请求mock数据

建立一个service.js对axios进行封装,让后通过service.js来统一请求mock数据,这样做的好处是在切到真实接口的时候可以更加灵活
service.js的代码如下

1
2
3
4
5
6
7
8
9
import axios from 'axios'
const api_rul = '' //mock 接口地址可以为空字符串,真实接口配置为真实的接口地址。
// create an axios instance
const service = axios.create({
baseURL: api_rul,
timeout: 5000 // request timeout
})

export default service

通过一个统一的调用接口文件请求mock数据
如mockapi.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import service from '@/utils/service'

export function getCategory() {
return service({
url: '/api/category',
method: 'get',
params: {}
})
}

export function getUserInfo() {
return service({
url: '/mock/api/getUserInfo',
method: 'get',
params: {}
})
}

在methods中进行方法的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 方法二:通过封装后的get方法获取数据
getUserInfo()
{
getUserInfo().then(res =>{
console.log(res.data)
this.userinfo = res.data.data
}
)
},
getCategory()
{
getCategory().then(res =>{
console.log(res.data)
this.categorys = res.data.data
}
)
}

在vue的组件中具体的调用和展示代码如下:
HelloWorld.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<template>
<h1>{{ msg }}</h1>
<div>
人员列表
</div>
<div>
<ul>
<li v-for="(user) in userinfo.list" :key="index">
{{ user.id }} : {{ user.name }} {{ user.age }} {{ user.email }}
</li>
</ul>
</div>
<div>
目录
</div>
<div>
<ul>
<li v-for="(category) in categorys" :key="index">
{{ category.id }} : {{ category.title }} {{ category.href }}
</li>
</ul>
</div>
</template>
<script >
import axios from 'axios'
import { getCategory,getUserInfo } from '../api/mockapi'

export default {
data() {
return {
msg: 'Welcome to Your Vue.js App',
userinfo: {},
categorys: []
};
},
mounted() {
this.getData()
this.getUserInfo()
this.getCategory()
},
methods: {
// 方法一:直接axios请求调用获取mock数据
async getData() {
await axios.get('/mock/api/getApiInfo').then(res =>{
console.log(res.data)
this.msg = res.data.title
}
)
},
// 方法二:通过封装后的get方法获取数据
getUserInfo()
{
getUserInfo().then(res =>{
console.log(res.data)
this.userinfo = res.data.data
}
)
},
getCategory()
{
getCategory().then(res =>{
console.log(res.data)
this.categorys = res.data.data
}
)
}
}
}
</script>

整个工程的目录结构说明如下:

mocktest工程目录

五、实际运行效果

mock效果
可以看到分别用两种方式获取mock数据的效果,其中人员列表中的数据是mock生成的模拟数。


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注微信公众号,一起学习、成长!

不忘初心,方得始终,码农实现自我提升的心法与工具

发表于 2024-08-20 | 更新于: 2025-04-08 | 分类于 人生 | | 阅读次数:
字数统计: 1.7k | 阅读时长 ≈ 5

在信息技术飞速发展的今天,越来越多的人进入到IT行业,也使得这个行业越来越卷。随着信息化普及进入尾声以及全球经济下行,IT行业也像传统的房地产行业一样哀鸿遍野,码农也像农民工一样转行的转行失业的失业。想要在这个行业里站住脚不被淘汰只能是不断的提升学习提升自己的能力,让自己成为不可替代才行。

作为码农,如是今还有份稳定的工作,应该来说是幸运的,但也是很焦虑的。一方面不知道自己所负责的业务还能撑多久,公司还能撑多久;一方面还得要思考一旦失业不知道自己的技术水平还能不能找到合适的工作。作为社会人,只有有了对抗风险的本钱后,才会有底气,有了底气后才会不至于那么的焦虑。而底气来自两个方面一方面是有足够的钱;另一方面是有足够的能力。如果有足够的钱,像文艺复兴时期的大咖们被人包养,吃喝不愁,那我们可以不用焦虑,惬意的写代码那一定是很开心的;如果能力足够强,其实也不用担心,换个地方施展自己的能力而已。而我们的现状是既要幸幸苦苦赚钱维持自己的生活又要不断的学习来提升自己的能力适应这个不断发展的行业。

如何在繁忙琐碎的编码工作与个人成长之间找到平衡,下面以我个人的经历来谈谈我的思考。对于码农来说,面临最大的两个问题是如何更好的利用时间和如何通过学习来提升自我的问题。

一、如何更好的利用时间?

在李笑来老师的《和时间做朋友》的书中讲到,其实时间是不可以管理的,每个人每天只有24小时,能够管理的是自己的精力,也就是把自己的关注力放到哪里。要学习,就应该把学习精力、注意力投入足够多的时间。对于我们来说最大的挑战来自手机,下班后很多同学报复性的休息放松,想起自己上班工作了,休息的时候一定得要彻底的放松,拿着手机刷抖音、打游戏、聊天不知不觉就到了深夜。为了避免长时间的玩手机,我的做法是到了一定时间把手机所有的应用都关闭,给自己一段没有手机打挠的时间,很多手机都提供的“禅定模式”,开启“禅定模式”后手机上除了接打电话,其他的应用都暂时不能用,除非退出“禅定模式”,通过这种方式让自己的注意力从手机上移开,放到看书和学习上来。在这里我常用的专注力APP是”Forest 专注森林“,它可以设置一段专注力时间,比如60分钟,如果60分钟你没有动手机就成功的种下了一颗健康的树,如果中途心痒痒玩了手机这个树就会蔫掉。可以按时间周期统计你的专注的时间。

Forest 专注森林

当然专注力是一方面,其实更重要的是我们应该有自控力的意识,有自我提升学习的意识。有了意识以后才会有行动。

二、如何通过学习来提升自我?

焦虑是因为面对残酷的社会竞争压力以及对自身能力的不自信。所以很多东西都想学,机器学习、网络安全、英语、写作等等。正因为焦虑,所以面临的困惑是什么都想学,什么都想学的结果是什么都没有学会。相信大多数人都有这样的经历,心想着要不断的提升自己,桌上摆了很多书,今天看几页这本书,明天翻几页那本书,看上去天天在看书,实际上一本书都没有看进去。看英语的时候在想应该多花点时间看看专业书,看专业书的时候在想英语也很重要,要不看会英语。实际就是有限的时间精力和无限的需要学习的知识之间的矛盾。尤其是专业领域,看了很多书,不能学以致用,看了就忘,感觉就是学了个寂寞。

早几年我也有相同的困惑,认识到学习,目标非常重要,没有明确目标的学习到头来都是浪费时间。于是写了一篇《你有了一个目标,于是你有了一堆技能,而不是反过来》。其实道理大家都懂,要有目标,不忘初心,方得始终。但是对于个人来说目标其实并不好确定,大部分人来说其实也没有什么明确的目标,我的经验是在没有明确的目标的时候就把考证当做目标,以考促学。见《工作这么多年了,我为什么还在考证》。后来我意识到自我提升最核心的是要构建自己知识体系,我的目标是构建了自己的知识体系,能够利用自己的知识体系具备“成事”的能力。如何建立个人知识体系,借用网上的一张图。

个人知识体系

有了构建自己知识体系的大目标后,我把自己近几年需要巩固提升的方面做了一个学习地图,有了学习地图就像航海的地图一样,避免东一下西一下迷失方向。

学习地图

刘未鹏在他的《暗时间》中有个观点让我感触特别的深刻,意思是你所懂得的多少并不是在于你看了多少书而是取决于你思考有多深。“教是最好的学”、“书写是更好的思考”。为了践行“问题->输入->内化->输出”,笃信写是为了更好的思考,坚持写作,力争更好的思考。我开启了自己的博客持续在CSDN和自己的博客上进行写作输出,将自己碰到的问题、经验、思考写出来,即帮助了大家又促进了自己,希望能和大家一起成长。


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

node20+版本下hexo部署报错失败的解决办法

发表于 2024-08-15 | 更新于: 2025-04-08 | 分类于 技术 | | 阅读次数:
字数统计: 864 | 阅读时长 ≈ 4

最近升级了node.js的版本,升到了最新的稳定版本v20.16.0,结果发现在该版本下hexo部署报错失败。本文记录了node20+版本下hexo部署报错失败的解决办法。

一、报错信息

执行hexo的deploy部署命令

1
hexo d

具体报错信息如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
INFO  Deploying: git
INFO Clearing .deploy_git folder...
INFO Copying files from public folder...
FATAL Something's wrong. Maybe you can find the solution here: https://hexo.io/docs/troubleshooting.html
TypeError: mode must be int32 or null/undefined
at copyFile (node:fs:3020:11)
at tryCatcher (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\util.js:16:23)
at ret (eval at makeNodePromisifiedEval (C:\Users\xiejava\AppData\Roaming\npm\node_modules\hexo-cli\node_modules\bluebird\js\release\promisify.js:184:12), <anonymous>:13:39)
at D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\hexo-fs\lib\fs.js:144:39
at tryCatcher (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:547:31)
at Promise._settlePromise (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:604:18)
at Promise._settlePromise0 (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:649:10)
at Promise._settlePromises (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:729:18)
at Promise._fulfill (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:673:18)
at Promise._resolveCallback (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:466:57)
at Promise._settlePromiseFromHandler (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:559:17)
at Promise._settlePromise (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:604:18)
at Promise._settlePromise0 (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:649:10)
at Promise._settlePromises (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:729:18)
at Promise._fulfill (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:673:18)
at Promise._resolveCallback (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:466:57)
at Promise._settlePromiseFromHandler (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:559:17)
at Promise._settlePromise (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:604:18)
at Promise._settlePromise0 (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:649:10)
at Promise._settlePromises (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:729:18)
at Promise._fulfill (D:\CloudStation\personal\xiejavablog\myhexo\myblog\node_modules\bluebird\js\release\promise.js:673:18)

遇到FATAL Something's wrong TypeError: mode must be int32 or null/undefined这类错误通常是在使用Hexo生成静态文件时出现的。这个问题通常与Hexo的一些插件不兼容或配置不当有关。

二、解决办法

一般来说因为node.js和hexo存在版本适配的关系,所以当可能是一个版本过高一个版本过低导致的出现问题。
解决这个问题可以降低node.js的版本,可以将hexo更新至适配的高版本。这里介绍如何将hexo更新至适配的高版本。

1、查看哪些包需要更新

1
npm outdated

在这里插入图片描述

通过npm outdated 列出了所有需要升级的组件包,这里还给出了npm也需要升级的信息,需要将npm从10.8.1升级到10.8.2,具体的升级命令是 npm install -g npm@10.8.2
执行 npm install -g npm@10.8.2 完成npm的升级

2、升级更新需要升级的包

升级hexo和hexo-cli

1
npm update hexo-cli hexo --latest

在这里插入图片描述

重新执行npm outdated
可以看到hexo 的版本从4.2.0升级到了4.2.1
在这里插入图片描述

重新执行hexo d,发现不报错了,并且可以成功部署。
这里还有hexo-abbrlink和hexo-generator-search 不是适配的版本,虽然不影响hexo部署,但也可以用同样的方法将其升为最新适配的版本。

1
npm update hexo-abbrlink hexo-generator-search --latest

在这里插入图片描述


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注微信公众号,一起学习、成长!

django+markdown2+pygments实现markdown解析及代码高亮

发表于 2024-08-14 | 更新于: 2025-04-08 | 分类于 技术 | | 阅读次数:
字数统计: 1.1k | 阅读时长 ≈ 4

随着markdown的流行,web应用系统常常会要碰到有使用markdown编辑器进行富文本编辑,然后在前台web页面进行显示。常见的博客系统当然也需要支持markdown的编辑与显示。本文就通过一个真实的博客系统来说明django+markdown2+pygments实现markdown解析及代码高亮。

一、后台管理支持markdown编辑

django应用的后台管理支持markdown可以用django-mdeditor,它是一个Django应用,它集成了markdown-editor,允许你在Django项目中使用富文本编辑器编写Markdown格式的内容。这个插件通常用于博客、论坛或任何需要用户输入Markdown文本的场景。

1、安装依赖

首先,通过pip安装django-mdeditor

1
pip install django-mdeditor

2、添加应用到INSTALLED_APPS

在settings.py文件中,将django_mdeditor添加到INSTALLED_APPS列表中,参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
INSTALLED_APPS = [
'blog',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'django_filters', # 注册条件查询
'mdeditor', # 注册markdown的应用
'drf_yasg2', # 接口文档
]

3、设置MEDIA_URL和MEDIA_ROOT

django-mdeditor使用文件上传功能,因此需要在settings.py中正确设置

1
2
3
MEDIA_URL和MEDIA_ROOT:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')

4、在模型中使用MdEditorField

在Django模型中,使用MdEditorField替换标准的TextField:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'''博客文章'''
class BlogPost(BaseModel):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=200, verbose_name='文章标题', unique = True)
category = models.ForeignKey(BlogCategory, blank=True,null=True, verbose_name='文章分类', on_delete=models.DO_NOTHING)
isTop = models.BooleanField(default=False, verbose_name='是否置顶')
isHot = models.BooleanField(default=False, verbose_name='是否热门')
isShow = models.BooleanField(default=False, verbose_name='是否显示')
summary = models.TextField(max_length=500, verbose_name='内容摘要', default='')
content = MDTextField(verbose_name='内容')
viewsCount = models.IntegerField(default=0, verbose_name="查看数")
commentsCount = models.IntegerField(default=0, verbose_name="评论数")
tags = models.ManyToManyField(to=Tag, related_name="tag_post", blank=True, default=None, verbose_name="标签")
blogSource = models.CharField(max_length=200, blank=True, null=True, default='',verbose_name='文章来源')
pubTime = models.DateTimeField(blank=True, null=True, verbose_name='发布日期')

@property
def tag_list(self):
return ','.join([i.tag for i in self.tags.all()])

def __str__(self):
return self.title

class Meta:
verbose_name = '博客文章'
verbose_name_plural = '博客文章'

在博客文章的模型中,文章内容需要支持markdown,所以content = MDTextField(verbose_name='内容')

5、查看效果

用django自带的后台管理admin就可以看到效果了

django自带的后台管理admin

二、前台支持markdown解析及代码高亮

在后台支持markdown编辑后,前台页面的博客文章页面也得要支持对markdown得解析。

1、安装依赖

在Django项目中使用markdown2库实现代码高亮,安装markdown2和pygments这两个Python库。markdown2用于解析Markdown文本,而pygments用于代码高亮。

1
pip install markdown2 pygments

2、配置Markdown解析器

在Django视图中,需要导入markdown2模块,并使用它来解析Markdown文本。同时,要启用fenced-code-blocks扩展,以便markdown2能正确识别代码块。

1
import markdown2

markdown2的扩展说明见 https://github.com/trentm/python-markdown2/wiki/Extras
在这里加入了

1
2
extras=["code-color", "fenced-code-blocks", "cuddled-lists", "tables",
"with-toc", "code-friendly"]

视图实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 详情页视图实现.
def post_detail(request, id):
try:
post_obj = BlogPost.objects.get(id=id)
html_content = markdown2.markdown(post_obj.content,
extras=["code-color", "fenced-code-blocks", "cuddled-lists", "tables",
"with-toc", "code-friendly"])
html_content = html_content.replace('<table>', '<table class="table table-bordered">')
html_content = html_content.replace('<img src=', '<img style="max-width:100%;height:auto;" src=')
context = {"post_obj": post_obj,
"html_content": html_content,
"hot_posts": get_hot_posts(),
"tags": get_all_tags(),
"post_grouped_by_year": get_post_groped_by_year(),
'categories': get_categories(),
'social_infos': get_socialinfo()}
except BlogPost.DoesNotExist:
raise Http404("Post does not exist")
return render(request, "blog/post.html", context)

3、在模板中显示HTML

在Django模板中,直接输出转换后的HTML内容。使用|safe过滤器告诉模板引擎不要转义HTML代码。

1
2
3
<div class="lyear-arc-detail">
{{ html_content|safe }}
</div>

4、导出高亮的css文件并引入css

有了上面的步骤,只是可以解析了markdown成html并显示,最终代码的高亮是通过css 来控制显示的,执行以下命令将高亮的css文件导出。

1
pygmentize -S default -f html -a .codehilite > markdown_highlighy.css

pyments的官方文档 https://pygments.org/ 查看一共有多少种风格,可以参考网址 https://pygments.org/docs/styles/#getting-a-list-of-available-styles
将生成的markdown_highlighy.css文件拷入到static/blog/css下
在模板页面中引入css

1
<link rel="stylesheet" type="text/css" href="{% static 'blog/css/markdown_highlighy.css' %}" />

5、查看效果

可以看到markdown可以正常解析,代码也可以高亮显示了。

在这里插入图片描述

三、全套代码

https://gitee.com/xiejava/ishareblog


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

一个人活成一个团队:python的django项目devops实战

发表于 2024-08-11 | 更新于: 2025-04-08 | 分类于 技术 | | 阅读次数:
字数统计: 1.5k | 阅读时长 ≈ 5

对于开发团队来说提高软件交付的速度和质量是一个永恒的话题,对于个人开发者来说同样如此。作为一个码农,一定会有几个自己私有的小项目,从需求管理到开发到测试到部署运维都得要自己来,将自己一个人活成一个团队。

DevOps(Development和Operations的组合),旨在通过自动化、协作和共享责任来提高软件开发和运维的效率、质量和安全性。作为一个人的团队,也可通过devops实践来提高对自己项目的效率和质量,使产品持续开发、持续集成、持续测试、持续部署、持续监控,非常频繁地发布新版本。本文就以一个实际的python的django项目来运用阿里的云效devops平台来进行实战。
在这里插入图片描述
DevOps平台工具有很多,最常见的就是大名顶顶的Jenkins,作为个人开发者要准备相应的硬件资源,还要要自己维护一套Jenkins有点麻烦。这里直接就选择成熟的阿里云效devops https://devops.aliyun.com/ ,这套平台基础版是免费的,对于个人开发者来说已经够用了。

一、需求规划

个人项目虽小,但是也得要有相应的规划,至少得有个需求清单来进行需求的规划和跟踪,哪些需求已经完成了,哪些还需要进行开发做到自己心中有数。
可以在云效的项目协作中创建一个项目进行管理。
在这里插入图片描述

在这里我创建了一个xiejava的博客项目
在这里插入图片描述

在这里我们就可以将自己规划的需求录入进来做好自己的需求跟踪清单
在这里插入图片描述

可以规划自己的版本,将需求跟踪清单里的需求纳入到版本迭代计划。
在这里插入图片描述

在迭代计划中可以看到这个迭代要完成的需求清单。
在这里插入图片描述

二、代码管理

即使是最简单的项目,建议还是通过代码仓库进行代码的版本管理,我的代码是放到码云https://gitee.com/xiejava/ishareblog 进行托管的,也可以托管到云效自己的代码管理仓库。
有了代码仓库,可以通过在云效构建流水线来进行自动构建、自动测试、自动部署了。

三、创建流水线

在云效中创建ishareblog的自动发布流水线,整个流水线包括获取代码、测试、构建、部署。
在这里插入图片描述

1、配置流水线源

流水线源可以配置云效自己的代码库,也可以配置其他的代码库,如我里是配置的码云代码库。
可以开启代码源触发,开启后一旦代码库有提交操作,就会自动触发流水线工作。
在这里插入图片描述

需要说明的是,如果是外部的代码仓库,需要在外部的代码仓库中添加Webhook触发设置

如我的是码云的仓库,就要在码云的仓库中添加Webhook的配置
在这里插入图片描述

四、自动测试

在测试环节,配置了python代码扫描和Python单元测试。
python代码扫描用的是云效默认的配置
比较麻烦的是Python单元测试,Python单元测试需要在Python项目中写测试用例,还要配置测试命令。
在Python项目中写测试用例见《django集成pytest进行自动化单元测试实战》。
配置测试命令就是在测试服务其中进行发布测试的所有shell命令
在这里插入图片描述

配置测试命令就是在测试服务其中进行发布测试的所有shell命令
作为一个django的项目测试命令参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# pytest default command
# 安装mysql客户端
sudo apt-get update
sudo apt-get install -y libmysqlclient-dev

# 安装新版本的SQLite3
# wget https://www.sqlite.org/2024/sqlite-autoconf-3460000.tar.gz

# 安装依赖
sudo pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
sudo pip install pysqlite3 -i https://pypi.tuna.tsinghua.edu.cn/simple
sudo pip install pysqlite3-binary -i https://pypi.tuna.tsinghua.edu.cn/simple

# 替换Django的sqlite3的驱动文件
sudo cp -f /root/workspace/ishareblog_J18t/change_set/base.py /usr/local/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py

# 初始化数据库
sudo python manage.py makemigrations --settings=ishareblog.settings_test
sudo python manage.py migrate --settings=ishareblog.settings_test

# 启动django服务
sudo nohup python manage.py runserver 8000 --settings=ishareblog.settings_test &

PORT=8000 # 替换为您想要检查的端口号
NEXT_COMMAND="sudo pytest --html=report/index.html" # 通过pytest进行单元测试

until nc -z localhost $PORT; do
echo "Port $PORT is not ready - waiting..."
curl http://localhost:8000
sleep 1
done

echo "Port $PORT is ready"
eval "$NEXT_COMMAND"

ps aux | grep python


# 通过pytest进行单元测试
#sudo pytest --html=report/index.html

pkill -f manage.py

ps aux | grep python

因为在单元测试中还做了接口测试,这里会要启动djang服务,进行接口测试,测试完成后还要停止服务。
可以在流水线执行完后查看扫描报告和测试报告
在这里插入图片描述

扫描报告
代码扫描报告,报出来的大部分是格式规范的问题。
在这里插入图片描述

测试报告
自动化测试报告是通过pytest测试完成形成的报告。
在这里插入图片描述

五、自动构建

自动构建将会将构建好的制品打包上传至构建服务器上。
在这里插入图片描述

六、自动部署

在这里插入图片描述

也可以配置部署后的通知邮件,比如部署成功或失败后发邮件通知。

在这里插入图片描述

最后通过统计报表可以看到流水线近段期间的执行情况

在这里插入图片描述

七、总结

DevOps通过自动化的流程,使得构建、测试、发布软件能够更加地快捷、频繁和可靠。本文通过一个python的django个人博客应用进行了DevOps的实战,通过DevOps拉通开发和运维,通过应用云效的DevOps平台实现自动化“软件交付”的流程,使得构建、测试、发布软件能够更加地快捷、频繁和可靠,提交研发交付效率。作为个人项目也是可以应用devops提高效率。


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

django快速实现个人博客(附源码)

发表于 2024-08-10 | 更新于: 2025-04-08 | 分类于 技术 | | 阅读次数:
字数统计: 3.7k | 阅读时长 ≈ 19

Django作为一款成熟的Python Web开发框架提供了丰富的内置功能,如ORM(对象关系映射)、Admin管理界面、URL分发、模板系统、表单处理等,使得开发者能够快速搭建Web应用,大幅提高了开发效率。以前写过一篇博文《Django+Vue快速实现博客网站》介绍了通过Djang+Vue快速实现博客网站,django+vue作为个人博客来说稍显复杂,部署起来也比较麻烦,Vue的单页面架构也不利于SEO,更简单的解决方案其实还是用django的模板系统快速构建web应用,对于个人博客来说部署和运维更加简单也利于SEO。下面介绍如何快速的通过django模板系统快速实现个人博客。

一、工程目录组织结构

在这里插入图片描述

二、模型及管理实现

模型及管理端的实现沿用《Django+Vue快速实现博客网站》文章中的实现,用Django搭建很快很简单。
模型很简单,根据博客要显示的内容包括有‘文章分类’、‘文章标签’、‘博客文章’、‘站点信息’、‘社交信息’、‘聚焦’,模型定义分别如下: 这里要说明的是因为博客文章内容准备用markdown编写,所以引入了mdeditor from mdeditor.fields import MDTextField 内容字段content=MDTextField(verbose_name='内容')
模型代码示例如下:

1、模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
from django.db import models
from common.basemodel import BaseModel
from mdeditor.fields import MDTextField
# Create your models here.
'''文章分类'''
class BlogCategory(BaseModel):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=50,verbose_name='分类名称',default='')
href = models.CharField(max_length=100,verbose_name='分类路径',default='')

def __str__(self):
return self.title

class Meta:
verbose_name = '文章分类'
verbose_name_plural = '文章分类'


'''文章标签'''


class Tag(BaseModel):
id=models.AutoField(primary_key=True)
tag=models.CharField(max_length=20, verbose_name='标签')

def __str__(self):
return self.tag

class Meta:
verbose_name='标签'
verbose_name_plural='标签'


'''博客文章'''
class BlogPost(BaseModel):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=200, verbose_name='文章标题', unique = True)
category = models.ForeignKey(BlogCategory, blank=True,null=True, verbose_name='文章分类', on_delete=models.DO_NOTHING)
isTop = models.BooleanField(default=False, verbose_name='是否置顶')
isHot = models.BooleanField(default=False, verbose_name='是否热门')
isShow = models.BooleanField(default=False, verbose_name='是否显示')
summary = models.TextField(max_length=500, verbose_name='内容摘要', default='')
content = MDTextField(verbose_name='内容')
viewsCount = models.IntegerField(default=0, verbose_name="查看数")
commentsCount = models.IntegerField(default=0, verbose_name="评论数")
tags = models.ManyToManyField(to=Tag, related_name="tag_post", blank=True, default=None, verbose_name="标签")
blogSource = models.CharField(max_length=200, blank=True, null=True, default='',verbose_name='文章来源')
pubTime = models.DateTimeField(blank=True, null=True, verbose_name='发布日期')

@property
def tag_list(self):
return ','.join([i.tag for i in self.tags.all()])

def __str__(self):
return self.title

class Meta:
verbose_name = '博客文章'
verbose_name_plural = '博客文章'


'''站点信息'''


class Site(BaseModel):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=50, verbose_name='站点名称', unique = True)
avatar = models.CharField(max_length=200, verbose_name='站点图标')
slogan = models.CharField(max_length=200, verbose_name='站点标语')
domain = models.CharField(max_length=200, verbose_name='站点域名')
notice = models.CharField(max_length=200, verbose_name='站点备注')
desc = models.CharField(max_length=200, verbose_name='站点描述')

def __str__(self):
return self.name

class Meta:
verbose_name = '站点信息'
verbose_name_plural = '站点信息'


'''社交信息'''


class Social(BaseModel):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=20, verbose_name='标题')
icon = models.CharField(max_length=200, verbose_name='图标')
color = models.CharField(max_length=20, verbose_name='颜色')
href = models.CharField(max_length=100, verbose_name='路径')

def __str__(self):
return self.title

class Meta:
verbose_name = '社交信息'
verbose_name_plural = '社交信息'


'''聚焦'''


class Focus(BaseModel):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=20, verbose_name='标题')
img = models.CharField(max_length=100, verbose_name='路径')

def __str__(self):
return self.title

class Meta:
verbose_name = '聚焦'
verbose_name_plural = '聚焦'


'''友链'''


class Friend(BaseModel):
id = models.AutoField(primary_key=True)
siteName = models.CharField(max_length=20, verbose_name='友链站点名称')
path = models.CharField(max_length=100, verbose_name='地址路径')
desc = models.CharField(max_length=200, verbose_name='描述')

def __str__(self):
return self.siteName

class Meta:
verbose_name = '友链'
verbose_name_plural = '友链'

2、admin管理

实际上只要把模型注册到admin就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from django.contrib import admin
from blog.models import *
# Register your models here.
@admin.register(BlogCategory)
class BlogCategoryAdmin(admin.ModelAdmin):
admin.site.site_title="ishareblog后台"
admin.site.site_header="ishareblog后台"
admin.site.index_title="ishareblog管理"

list_display = ['id', 'title', 'href']

@admin.register(BlogPost)
class BlogPostAdmin(admin.ModelAdmin):
list_display = ['title','category','isTop','isHot']
search_fields = ('title',)

@admin.register(Site)
class SiteAdmin(admin.ModelAdmin):
list_display = ['name','slogan','domain','desc']

@admin.register(Social)
class SocialAdmin(admin.ModelAdmin):
list_display = ['title','href']

@admin.register(Focus)
class FoucusAdmin(admin.ModelAdmin):
list_display = ['title','img']

@admin.register(Friend)
class FoucusAdmin(admin.ModelAdmin):
list_display = ['siteName','path','desc']

@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ['id','tag']

三、博客展现实现

博客前端展现用django的模板技术实现。在网上找了一个基于Bootstrap v4.3.1的小清新风格HTML博客模板,https://gitee.com/yinqi/Light-Year-Blog 这个博客模只有三个页面,首页,详细页和About页面,样式和js都不多,比较简单。将html模板放入到templates的blog目录,为了便于维护将一些公共部分抽到了base.html,index.html和post.html 通过{ % extends 'blog/base.html' % }进行应用

1、视图实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
from django.http import HttpResponse, Http404
from django.template import loader
from django.core.paginator import Paginator
from blog.models import BlogPost, Tag, BlogCategory
from django.shortcuts import render
from django.db.models import Count
from django.db.models.functions import TruncYear

import markdown2


# 首页/列表页视图实现.
def index(request):
category_id = request.GET.get('category')
tag_id = int(request.GET.get('tag',0))
year = request.GET.get('year')
search = request.GET.get('search')
if category_id:
blogpost_list = BlogPost.objects.filter(category=category_id, isShow=True).order_by('-isTop', '-pubTime')
elif tag_id:
blogpost_list = BlogPost.objects.filter(tags__id=tag_id, isShow=True).order_by('-isTop', '-pubTime')
elif year:
blogpost_list = BlogPost.objects.filter(pubTime__year=year, isShow=True).order_by('-isTop', '-pubTime')
elif search:
blogpost_list = BlogPost.objects.filter(content__icontains=search, isShow=True).order_by('-isTop', '-pubTime')
else:
# 筛选出需要显示的博客文章
blogpost_list = BlogPost.objects.filter(isShow=True).order_by('-isTop', '-pubTime', '-update_time')
# 每页显示的数量
per_page = 10

# 创建分页器实例
paginator = Paginator(blogpost_list, per_page)

# 获取当前页码,如果没有提供,则默认为第一页
page_number = request.GET.get('page') or 1

# 获取当前页的数据
page_obj = paginator.get_page(page_number)

# 计算显示的页码范围
current_page = int(page_number)
pages_to_show = 11 # 当前页前后各5页加上当前页共11页
start_page = max(current_page - 5, 1)
end_page = min(start_page + pages_to_show - 1, paginator.num_pages)

template = loader.get_template("blog/index.html")
context = {
"page_obj": page_obj,
'start_page': start_page,
'end_page': end_page,
'hot_posts': get_hot_posts(),
'tags': get_all_tags(),
'post_grouped_by_year':get_post_groped_by_year(),
'categories': get_categories(),
'category_id': category_id,
'tag_id': tag_id,
'year': year,
'search': search,
}
return HttpResponse(template.render(context, request))


# 详情页视图实现.
def post_detail(request, id):
try:
post_obj = BlogPost.objects.get(id=id)
html_content = markdown2.markdown(post_obj.content,
extras=["code-color", "fenced-code-blocks", "cuddled-lists", "tables",
"with-toc", "highlightjs-lang"])
html_content = html_content.replace('< table >', '< table class="table table-bordered" >')
html_content = html_content.replace('< img src=', '< img style="max-width:100%;height:auto;" src= ')
context = {"post_obj": post_obj, "html_content": html_content, "hot_posts": get_hot_posts(),"tags": get_all_tags(),"post_grouped_by_year":get_post_groped_by_year(),'categories': get_categories()}
except BlogPost.DoesNotExist:
raise Http404("Post does not exist")
return render(request, "blog/post.html", context)


def get_hot_posts():
# 获取点赞数最高的前5篇文章
hot_posts = BlogPost.objects.filter(isShow=True).order_by('-viewsCount', '-pubTime')[:5]
return hot_posts


def get_all_tags():
# 获取所有的标签
tags = Tag.objects.all() # 获取所有的标签
return tags

def get_post_groped_by_year():
# 将发布日期截断为年份,并计算每年的文章数量。
post_grouped_by_year = (
BlogPost.objects
.annotate(year=TruncYear('pubTime'))
.values('year') # 返回的字典包含'year'键
.annotate(publication_count=Count('id')) # 计算每年的文章数量
.order_by('-year') # 按年排序
)
return post_grouped_by_year

def get_categories():
# 获取所有分类
categories = BlogCategory.objects.all()
return categories

2、模板实现

静态文件如css、js等放到static的blog目录,html模板文件放到templates的blog目录
在setting.py文件中配置 STATIC_URL = 'static/',在html模板文件中通过{ % load static % } 将静态文件的地址引用进来
将公共部分抽取出来形成base.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
{ % load static % }
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>XieJava的博客</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="author" content="xiejava" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="{ % static 'blog/css/bootstrap.min.css' % }" />
<link rel="stylesheet" type="text/css" href="{ % static 'blog/css/materialdesignicons.min.css' % }" />
<link rel="stylesheet" type="text/css" href="{ % static 'blog/css/style.min.css' % }" />
</head>
<body>
<header class="lyear-header text-center" style="background-image:url(images/left-bg.jpg);">
<div class="lyear-header-container">
<div class="lyear-mask"></div>
<h1 class="lyear-blogger pt-lg-4 mb-0"><a href="{ % url 'index' % }">XieJava的博客</a></h1>
<nav class="navbar navbar-expand-lg">
<a class="navbar-toggler" data-toggle="collapse" data-target="#navigation" aria-controls="navigation" aria-expanded="false" aria-label="Toggle navigation">
<div class="lyear-hamburger">
<div class="hamburger-inner"></div>
</div>
</a>

<div id="navigation" class="collapse navbar-collapse flex-column">
<div class="profile-section pt-3 pt-lg-0">
<img class="profile-image mb-3 rounded-circle mx-auto" src="https://img9.doubanio.com/icon/ul70489051-4.jpg" width="120" height="120" alt="xiejava" >
<div class="lyear-sentence mb-3">
记录最好的自己<br>
写是为了更好的思考,坚持写作,力争更好的思考。
</div>
<hr>
</div>

<ul class="navbar-nav flex-column text-center">
<li class="nav-item active">
<a class="nav-link" href="{ % url 'index' % }">首页</a>
</li>
{ % for category in categories % }
<li class="nav-item">
<a class="nav-link" href="{ % url 'index' % }?category={ { category.id } }">{ { category.title } }</a>
</li>
{ % endfor % }
<li class="nav-item">
<a class="nav-link" href="{ % url 'index' % }">关于我</a>
</li>
</ul>

<div class="my-2 my-md-3">
<form class="lyear-search-form form-inline justify-content-center pt-3">
<input type="text" id="search" name="search" class="form-control mr-md-1" placeholder="搜索关键词" />
</form>
</div>
</div>
</nav>
</div>
</header>
<div class="lyear-wrapper">
<section class="mt-5 pb-5">
<div class="container">

<div class="row">
<!-- 文章列表 -->
<div class="col-xl-8">
<!-- 内容 -->
{ % block content % }
<!-- 默认内容 -->
{ % endblock % }
</div>
<!-- 内容 end -->

<!-- 侧边栏 -->
<div class="col-xl-4">
<div class="lyear-sidebar">
<!-- 热门文章 -->
<aside class="widget widget-hot-posts">
<div class="widget-title">热门文章</div>
<ul>
{ % for post in hot_posts % }
<li>
<a href="{ % url 'post_detail' id=post.id % }">{ { post.title } }</a> <span>{ { post.pubTime } }</span>
</li>
{ % endfor % }
</ul>
</aside>

<!-- 归档 -->
<aside class="widget">
<div class="widget-title">归档</div>
<ul>
{ % for post in post_grouped_by_year % }
<li><a href="{ % url 'index' % }?year={ { post.year|date:'Y' } }" >{ % if year == post.year|date:'Y' % }<b>{ { post.year|date:'Y' } } 年 </b>{ % else % }{ { post.year|date:'Y' } } 年{ % endif % }</a> ({ { post.publication_count } })</li>
{ % endfor % }
</ul>
</aside>

<!-- 标签 -->
<aside class="widget widget-tag-cloud">
<div class="widget-title">标签 </div>
<div class="tag-cloud">
{ % for tag in tags % }
<a href="{ % url 'index' % }?tag={ { tag.id } }" { % if tag_id == tag.id % }class="badge badge-primary"{ % else % }class="badge badge-light"{ % endif % }>{ { tag.tag } }</a>
{ % endfor % }
</div>
</aside>
</div>
</div>
<!-- 侧边栏 end -->
</div>

</div>
<!-- end container -->
</section>
</div>
<script type="text/javascript" src="{ % static 'blog/js/jquery.min.js' % }"></script>
<script type="text/javascript" src="{ % static 'blog/js/jquery.nicescroll.min.js' % }"></script>
<script type="text/javascript" src="{ % static 'blog/js/bootstrap.min.js' % }"></script>
<script type="text/javascript" src="{ % static 'blog/js/main.min.js' % }"></script>
</body>
</html>

博客首页/列表页
通过{ % extends 'blog/base.html' % } 将公共部门引入进来后index.html的内容就简洁了很多
index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

{ % extends 'blog/base.html' % }

<!-- 内容 -->
{ % block content % }
{ % if page_obj.object_list.count > 0 % }
{ % for blogpost in page_obj.object_list % }
<article class="lyear-arc">
<div class="arc-header">
<h2 class="arc-title"><a href="article/{ { blogpost.id } }">{ { blogpost.title } }</a></h2>
<ul class="arc-meta">
<li><i class="mdi mdi-calendar"></i> { { blogpost.pubTime } }</li>
<li><i class="mdi mdi-tag-text-outline">
</i> { % for tag in blogpost.tags.all % }<a href="{ % url 'index' % }?tag={ { tag.id } }">{ { tag.tag } }</a>&nbsp{ % endfor % }</li>
<!--<li><i class="mdi mdi-comment-multiple-outline"></i> <a href="#">3 评论</a></li>-->
<li><i class="mdi mdi-heart-outline"></i> <a href="#">{ { blogpost.viewsCount } } 喜欢</a></li>
</ul>
</div>

<div class="arc-synopsis">
<p>{ { blogpost.summary } }</p>
</div>
</article>
{ % endfor % }


<!-- 分页 -->
<div class="row">
<div class="col-lg-12">
<ul class="pagination">
{ % if page_obj.has_previous % }
<li class="page-item"><a class="page-link" href="?page={ { page_obj.previous_page_number } }"><i class="mdi mdi-chevron-left"></i></a></li>
{ % endif % }

{ % for page_no in page_obj.paginator.page_range % }
{ % if page_no >= start_page and page_no <= end_page % }
{ % if page_no == page_obj.number % }
<li class="page-item active"><a class="page-link" href="#">{ { page_no } }</a></li>
{ % else % }
<li class="page-item"><a class="page-link" href="?page={ { page_no } }{ % if tag_id % }&tag={ { tag_id } }{ % endif % }{ % if year % }&year={ { year } }{ % endif % }{ % if search % }&search={ { search } }{ % endif % }">{ { page_no } }</a></li>
{ % endif % }
{ % endif % }
{ % endfor % }

{ % if page_obj.has_next % }
<li class="page-item"><a class="page-link" href="?page={ { page_obj.next_page_number } }{ % if tag_id % }&tag={ { tag_id } }{ % endif % }{ % if year % }&year={ { year } }{ % endif % }{ % if search % }&search={ { search } }{ % endif % }"><i class="mdi mdi-chevron-right"></i></a></li>
{ % endif % }

<p>总页数: { { page_obj.paginator.num_pages } }</p>
</ul>
</div>
</div>
{ % else % }
<p> 没有找到文章 </p>
{ % endif % }
<!-- 分页 end -->
{ % endblock % }
<!-- 内容 end -->

博客详情页post.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{ % extends 'blog/base.html' % }
<!-- 文章阅读 -->

{ % block content % }

<article class="lyear-arc">
<div class="arc-header">
<h2 class="arc-title"><a href="#">{ { post_obj.title } }</a></h2>
<ul class="arc-meta">
<li><i class="mdi mdi-calendar"></i> { { post_obj.pubTime } }</li>
<li> { % for tag in post_obj.tags.all % }<a href="{ % url 'index' % }?tag={ { tag.id } }">{ { tag.tag } }</a>{ % endfor % }</li>
<!--<li><i class="mdi mdi-comment-multiple-outline"></i> <a href="#">3 评论</a></li>-->
<li><i class="mdi mdi-heart-outline"></i> <a href="#">{ { post_obj.viewsCount } } 喜欢</a></li>
</ul>
</div>

<div class="arc-preview">
<img src="images/blog/post-1.png" alt="" class="img-fluid rounded" />
</div>

<div class="lyear-arc-detail">
{ { html_content|safe } }
</div>

</article>

{ % endblock % }
<!-- 内容 end -->

四、部署及效果

在部署之前执行python manage.py collectstatic 将admin等其他模块用到的静态文件统一输出到static的目录。
通过 python manage.py runserver 启动应用就可以看到效果。
实际效果见 http://iblog.ishareread.com/
博客首页
在这里插入图片描述

博客详情页
在这里插入图片描述

五、源代码

所有源代码及说明见 https://gitee.com/xiejava/ishareblog


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

django集成pytest进行自动化单元测试实战

发表于 2024-08-03 | 更新于: 2025-04-08 | 分类于 技术 | | 阅读次数:
字数统计: 1.3k | 阅读时长 ≈ 5

在Django项目中集成Pytest进行单元测试可以提高测试的灵活性和效率,相比于Django自带的测试框架,Pytest提供了更为丰富和强大的测试功能。本文通过一个实际项目ishareblog介绍django集成pytest进行自动化单元测试实战。

一、引入pytest相关的包

1
2
3
pip install pytest
pip install pytest-django
pip install pytest-html

其中pytest-django插件,它提供了Django和Pytest之间的桥梁,pytest-html 是一个 pytest 的插件,用于生成详细的 HTML 测试报告。这个插件能够将 pytest 运行的结果转化为一个直观、易于阅读的 HTML 格式报告,这对于分享测试结果、审查测试覆盖率以及归档测试历史非常有帮助。

二、配置pytest

1、将django的配置区分测试环境、开发环境和生产环境

因为测试环境、开发环境和生产环境的环境配置参数不一样,一个好的实践是将开发、测试和生产环境通过配置区分开,django的配置主要集中在项目的settings.py文件,这里通过settings.py的配置文件将开发、测试、生产区分开,不同的环境调用不通的配置文件。

在这里插入图片描述

因为大部分的配置参数都是一样的,在这里我将公共的配置参数都抽到了base.py,环境配置中有差异的部分分别放到各自的配置文件中,如开发环境用的是mysql,测试环境用sqlite3,就可以将不同的配置给区分开。
测试环境是settings_test.py,这里除了数据库的配置不一样,其他都沿用基础的公共配置。settings_test.py配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
from .base import *

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'test_db.sqlite3'),
}
}

2、配置pytest

在Django项目根目录下,创建或编辑pytest.ini文件,来配置Pytest。
在这里插入图片描述

pytest.ini代码如下:

1
2
3
4
[pytest]
DJANGO_SETTINGS_MODULE = ishareblog.settings_test

python_files = tests.py test_*.py *_tests.py

DJANGO_SETTINGS_MODULE = ishareblog.settings_test 指定了pytest用到的环境配置
python_files = tests.py test_*.py *_tests.py 指定了pytest将测试以test开头的py文件中的测试用例。

三、编写测试用例

接下来,可以在tests.py或test_*.py文件中编写你的测试用例。由于pytest-django插件的存在,你可以像平常一样使用Django的测试机制,同时也能享受Pytest带来的便利。以下以我的ishareblog博客代码通过业务测试和接口测试来编写测试用例。

在这里插入图片描述

1、业务测试

我的isharebog业务相对简单,主要是测试验证业务模型模块的增删改查是否符合预期。
业务测试tests.py示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import pytest
from django.test import TestCase
from blog.models import BlogCategory

@pytest.mark.django_db
class TestBlogCategory(TestCase):

def setUp(self):
self.blogcategory = BlogCategory.objects.create(id=1,title="Test Category", href='/category/1')

def test_BogCategoryModel(self):
blog_category = BlogCategory.objects.get(id=self.blogcategory.id)
self.assertEqual(blog_category.title, "Test Category")
self.assertEqual(blog_category.href, '/category/1')


@pytest.mark.django_db
def test_blog_category_create():
blogcategory = BlogCategory.objects.create(id=1,title="Test Category", href='/category/1')
category_count = BlogCategory.objects.count()
assert category_count > 0, "Blog category was not created category_count=0."
assert blogcategory.id > 0, "Blog category was not created."
assert blogcategory.title == "Test Category", "Blog category title is wrong."
assert blogcategory.href == "/category/1", "Blog category href is wrong."


@pytest.mark.django_db
def test_blog_category_query():
category_count = len(BlogCategory.objects.all())
assert category_count >= 0, "Blog category query error."


if __name__ == '__main__':
pytest.main(["-s", "-v", "-p", "no:warnings", "--tb=short", "--html=report.html", "blog/tests.py"])

业务测试举了通过测试类和测试方法写的测试用例,分别对博客目录进行添加和查询编写了测试用例。

2、接口测试

接口是暴露给前端程序调用的,接口测试主要是测试接口正不正常,接口值是不是符合预期。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
import pytest

host = "http://localhost:8000"


class TestApi:
def test_getcategory_list(self):
url = f'{host}/api/category/'
response = requests.get(url)
assert response.status_code == 200, f'Expected status code 200 but got {response.status_code}'
assert response.json() != None, f'Expected to get json response but got {response.text}'
print(response.json())

def test_getpost_list(self):
url = f'{host}/api/post/list'
response = requests.get(url)
assert response.status_code == 200, f'Expected status code 200 but got {response.status_code}'
assert response.json() != None, f'Expected to get json response but got {response.text}'


if __name__ == '__main__':
pytest.main(["-s", "-v", "-p", "no:warnings", "--tb=short", "--html=report.html", "api/tests.py"])

接口测试部分,对获取目录的API接口和文章列表的API接口编写了测试用例。

四、进行测试

最后可以分别在blog目录和api目录下运行test.py 分别进行业务和接口的单元测试。
注意在进行测试之前需要执行 python manage.py makemigrations --settings=ishareblog.settings_test 初始化环境。
在进行api接口测试之前需要将django的应用服务启动 python manage.py runserver 8000 --settings=ishareblog.settings_test 启动的时候也带上测试环境的配置。
可以通过pytest --html=report.html 自动执行所有的单元测试,并生成可读的html的测试报告。
在这里插入图片描述

pytest生成的report.html测试报告
在这里插入图片描述

以上通过一个ishareblog的实际项目介绍django集成pytest进行自动化单元测试实战。
ishareblog的所有代码包括pytest的配置见 https://gitee.com/xiejava/ishareblog


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

解决django与sqlite3不兼容报SQLite 3.9.0 or later is required (found 3.8.2)错的问题

发表于 2024-07-23 | 更新于: 2025-04-08 | 分类于 技术 , 开发 | | 阅读次数:
字数统计: 331 | 阅读时长 ≈ 1

今天在尝试用pytest进行django的单元测试,pytest用的数据库是sqlite3,在window环境下测试得好好的,但是放到linux环境下就报错,具体是报django.core.exceptions.ImproperlyConfigured: SQLite 3.9.0 or later is required (found 3.8.2).的错。

在这里插入图片描述

从报错的提示看是sqlite3的版本太低,期望是3.9.0但是当前版本是3.8.2
在网上找了很多资料,也都是说django与sqlite3的版本不兼容,需要升级sqlite3的版本。
于是将sqlite3升级到目前的稳定版本3.46.0,然而发现并没有什么用,还是报sqlite3.NotSupportedError: deterministic=True requires SQLite 3.8.3 or higher 。

在这里插入图片描述

通过sqlite3 –version 查看版本号已经是3.46.0了,但还是提示要求SQLite版本在3.8.3以上。重装django4和python3.8的环境都没有用。
最后在网上找到解决办法。使用第三方包pysqlite3运行SQLite3
具体方法如下:
1、安装pysqlite3和pysqlite3-binary

1
2
pip install pysqlite3
pip install pysqlite3-binary

2、找到django的sqlite3驱动包,/usr/local/lib/python3.8/site-packages/django/db/backends/sqlite3/base.py 找到 from sqlite3 import dbapi2 as Database 注释它,添加代码

1
2
#from sqlite3 import dbapi2 as Database  #注释它
from pysqlite3 import dbapi2 as Database #新加这段代码

历经周折终于解决。


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

什么是软件定义安全SDSec

发表于 2024-07-09 | 更新于: 2025-04-08 | 分类于 技术 , 网络安全 | | 阅读次数:
字数统计: 2.4k | 阅读时长 ≈ 8

一、软件定义安全SDSec产生的背景

软件定义安全(Software Defined Security,SDSec)的产生背景主要源于传统网络安全防护方法在面对复杂网络环境时的不适应性,以及软件定义网络(SDN)技术的发展和应用。

SDN技术影响与数据与控制分离的理念:SDN的出现将网络的控制平面与数据平面分离,实现了网络资源的集中管理和自动化配置。SDN控制器可以全局视角管理网络,这为安全策略的统一规划和执行提供了可能。SDSec的核心理念是数据与控制分离,安全管理与控制集中化,这与SDN的内在性质相契合,适合用于网络安全的场景。

复杂网络环境与传统安全设备的挑战:在物理与虚拟网络共存的数据中心等复杂环境中,传统的网络安全设备部署过程繁复,不能灵活地区分处理流经的流量,安全防护范围僵化,且安全设备可能成为单一故障点,传统的安全网关设备如防火墙、入侵防护系统等,存在互操作性差、难以集成等问题,SDN的理念可以拓展到这些设备上,作为下一代安全产品开发的指导思想,从而产生了SDSec的概念

云计算和虚拟化技术的发展对安全的需求:云计算系统的开放API、虚拟化技术的资源池能力、SDN的支持,以及中小型企业对安全防护系统有效性、便捷性和灵活性的需求,促使软件定义安全理念在云计算安全防护中得到体现。

SDSec的产生是为了解决传统网络安全方法在现代网络环境中的局限性,同时利用SDN技术的优势,实现更高效、灵活和自动化的网络安全防护。

二、软件定义安全SDSec的定义

软件定义安全(Software Defined Security,SDSec)是一种从软件定义网络(SDN)引申而来的概念,其核心原理是将网络安全设备与其接入模式、部署方式、实现功能进行解耦。这种解耦使得底层的网络安全设备可以抽象为安全资源池中的资源,而顶层则通过软件编程的方式进行智能化、自动化的业务编排和管理,以完成相应的安全功能,实现灵活的安全防护 。

SDSec的工作机制可以分解为三个主要部分:软件定义流量、软件定义资源和软件定义威胁模型。这三个部分相互关联,形成一个动态、闭环的工作模型。具体来说:
● 软件定义流量通过软件编程实现网络流量的细粒度定义及转发控制管理,将目标网络流量转发到安全设备上,实现安全设备的逻辑部署和使用。
● 软件定义资源通过管理中心对安全资源进行统一注册、池化管理、弹性分配,并在虚拟计算环境下支持虚拟安全设备模板的分发和设备的创建。
● 软件定义威胁模型涉及自动化采集、分析和挖掘网络流量、网络行为、安全事件等信息,实现对未知威胁或高级安全威胁的实时分析和建模,并用建模结果指导流量定义,实现动态、闭环的安全防护。

SDSec的架构设计使得安全策略执行点(数据平面)与安全控制器(控制平面)相互分离,从而使安全设备能够快速、自动地适应业务的动态变化。这种分离的架构有助于厂商集中精力研发异常检测技术,提高安全产品的核心能力,并便于在一个计算能力更强的、开放的、综合的平台上完成异常检测

三、软件定义安全SDSec的支撑技术

软件定义安全本质上是一种技术理念,主要技术思路为参考 SDN 的数 据与控制层面分离 ,通过构建上层安全管理平台去运营、运维下层集约化部署的安 全资源。软件定义安全SDSec的主要支撑技术包括软件定义网络 (SDN)、虚拟化技术、API和标准化接口、安全编排与自动化响应 (SOAR)

软件定义网络 (SDN):SDN是SDSec的基础之一,它将网络的控制平面与数据平面分离,允许对网络流量进行集中控制和策略实施,为安全策略的灵活部署和动态调整提供了可能。
虚拟化技术:虚拟化技术支持快速准备虚拟化的安全设备,包括服务器虚拟化、网络功能虚拟化(NFV)和软件定义存储(SDS),这些技术允许安全功能如防火墙、入侵检测系统(IDS)、入侵防御系统(IPS)等作为虚拟实例运行,并灵活调度计算、存储、网络资源,可以更容易地在不同位置之间移动和扩展,为安全功能服务。
API和标准化接口:SDSec依赖于API和标准化接口来集成不同的安全组件和服务,允许不同供应商的产品之间进行互操作,增强整体安全生态系统的灵活性和可扩展性。
安全编排与自动化响应 (SOAR):自动化工具和工作流编排用于实现安全策略的快速部署、更新和响应。这包括安全策略的自动化生成、配置和变更管理,以及在检测到威胁时的自动响应。SOAR平台结合了安全事件管理、自动化响应和编排功能,用于协调多个安全工具和流程,提高安全团队的效率和响应速度。

这些技术共同作用,使SDSec能够提供一个更加强大、灵活和响应迅速的安全框架,以应对不断变化的威胁环境。

四、软件定义安全SDSec的优缺点

软件定义安全(SDSec)与传统安全产品相比,各有其独特的优点和缺点:

软件定义安全(SDSec) 传统安全产品
灵活性与可扩展性 使用SDN和NFV技术,安全策略可以动态配置和调整,适应网络流量变化和新的安全威胁。可以通过软件更新和配置更轻松地适应新的安全需求和技术进展。 通常使用硬件设备,配置和更新安全策略较为繁琐,不够灵活。硬件设备的功能和性能受到限制,升级和扩展可能需要更换设备或增加新的硬件。
集中化管理和自动化 可以通过集中的安全策略控制器管理整个网络的安全策略,实现自动化响应和安全事件管理。 管理分散在各个设备上,安全策略的更新和管理通常需要更多的人工干预。
资源利用率和成本效益 利用NFV将安全功能虚拟化在通用服务器上运行,提高了资源利用率,并降低了成本。 需要购买和维护多个专用硬件设备,成本和资源利用率不如虚拟化解决方案高效。
技术成熟度和部署复杂性 相较传统安全产品,SDSec 的技术可能需要更多时间来成熟,并且在部署和管理上可能存在一定的复杂性。 技术相对成熟,部署相对简单,但可能缺乏SDSec中的一些先进功能和灵活性。
安全性考量 虽然提供了灵活和智能的安全防护,但在实施时需要确保其本身不会成为攻击目标或单点故障。如果控制平台受到攻击,可能会对整个网络的安全造成影响。 可能因为使用独立的硬件设备,一些传统攻击方式可能更难以实施。

SDSec通过软件定义的方式提供了更灵活、智能和高效的安全解决方案,尤其适合于需要频繁更新和动态调整安全策略的现代网络环境。然而,与传统安全产品相比,SDSec在技术成熟度、部署复杂性和对网络基础设施的依赖性等方面可能存在一些挑战和限制。

需要注意的是,软件定义安全理念从逻辑上和架构上是涵盖了传统安全与云计算安全的,前者是从改变安全技术架构去提高安全管理效率,提升安全运营的 价值,而后者则是区别于安全落地的不同场景。因此软件定义安全同样适用于传统 IT 环境,如果做到了构建统一的上层管理平台,使其具备开放接口,下层各类安全 组件资源可受上层管理应用进行编排、计量等手段统一关联起来,那么这套安全防 护体系也可认为是由软件定义的。


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

常见网络攻击方式及防御方法

发表于 2024-07-04 | 更新于: 2025-04-08 | 分类于 技术 , 网络安全 | | 阅读次数:
字数统计: 2k | 阅读时长 ≈ 6

网络安全威胁的不断演变和增长,网络攻击的种类和数量也在不断增加,攻防对抗实战演练在即,让我们一起了解一下常见网络攻击方式及防御方法。

1. DDOS攻击(分布式拒绝服务攻击)

借助于C/S(客户端/服务器)技术,将多个计算机联合起来作为攻击平台,对一个或多个目标发动DDOS攻击,从而成倍地提高拒绝服务攻击的威力。
防护方法:
所有的主机平台都有低于DDOS的设置,基本的有:

  • 关闭不必要的服务
  • 限制同时打开的syn半连接数目
  • 缩短syn半连接的time out时间
  • 及时更新补丁

网络设置:
防火墙

  • 禁止对主机的非半开服务的访问,限制SYN的连接数和IP访问
  • 路由器
  • 设置SYN数据包流量速率

2. UDP洪水攻击

利用含有udp数据包的ip数据包对目标主机上的随机端口进行饱和攻击,由于udp流量不需要像tcp那样三次握手,可以低成本的运行。这种特质也使得udp非常脆弱,更容易被滥用,一些udp洪水攻击能够利用dns方法攻击的形式实施。
防护方法:
根据业务UDP最大包长设置UDP最大包大小以过滤异常流量。
建立UDP连接规则,要求所有去往该端口的UDP包,必须首先与TCP端口建立TCP连接。

3. Smurf攻击

攻击者向网络广播地址发送ICMP包,并将回复地址设置成受害网络的广播地址,通过使用ICMP应答请求数据包来淹没受害主机的方式进行,最终导致该网络的所有主机都对次ICMP应答请求作出答复,导致网络阻塞。更加复杂的Smurf攻击攻击将源地址改为第三方受害者,最终导致第三方崩溃。
防护方法:
1.配置路由器禁止IP广播包进网
2.配置网络上所有计算机的操作系统,禁止对目标地址为广播地址的ICMP包响应
3.对于从本网络向外部网络发送的数据包,本网络应该将其源地址为其他网络的这部分数据包过滤掉

4. CC攻击

CC攻击利用代理服务器向网站发送大量需要较长计算时间的URL请求,如数据库查询等,导致服务器进行大量计算而很快达到自身的处理能力而形成DOS,而攻击者一旦发送请求给代理后就主动断开连接,因为代理并不因为客户端这边连接的断开就不去连接目标服务器,因此攻击机的资源消耗相对很小,而从目标服务器看来,来自代理的请求都是合法的。
防护方法:
CC有效性在于攻击方不接受服务器回应的数据,发送完请求后就主动断开连接,因此要确认连接是否是CC,服务器端不立即执行URL请求命令,而是简单的返回一个页面转向的回应,回应中包含新的URL请求地址,如果是正常访问,客户端会主动再次连接到转向页面,对用户来说是透明的;而对于CC攻击者,由于不接收回应数据,因此就不会重新连接,服务器也就不需要进行查询操作。

5. ARP攻击(中间人攻击)

通过伪造IP地址和MAC地址实现ARP欺骗,能够在网络中产生大量的ARP通信量使网络阻塞,攻击者只要持续不断的发出伪造的ARP相应包就能更改目标主机ARP缓存中的IP-MAC条目,造成网络终端或中间人攻击。
防护方法:

  • 网关和终端双向绑定IP和MAC地址
  • 局域网中的每台电脑中进行静态ARP绑定
  • 打开安全防护软件的ARP防火墙功能
  • 彻底追踪查杀ARP病毒

6. 邮件钓鱼

利用伪装的电邮,欺骗收件人将账号、口令等信息回复给指定的接收者;或引导收件人连接到特制的网页,这些网页通常会伪装成和真实网站一样,如银行或理财的网页,令登录者信以为真,输入信用卡或银行卡号码、账户名称及密码等而被盗取。
防护方法:

  • 不点击不知来源的邮件和附件
  • 在邮箱服务端安装安全软件,开启SPF策略
  • 安装个人电脑杀毒软件

拓展:

  • 鱼叉攻击
    攻击者将木马程序作为电子邮件的附件,并起上一个极具诱惑力的名称,发送给目标电脑,诱使受害者打开附件,从而感染木马。
  • 水坑攻击
    攻击者分析攻击目标的上网活动规律,寻找攻击目标经常访问的网站的弱点,先将此网站“攻破”并植入攻击代码,一旦攻击目标访问该网站就会“中招”。

7. WIFI钓鱼

WIFI钓鱼是一种新型的无线网络攻击方式,将中间人攻击和钓鱼攻击相结合,选定目标路由器后,将连接到路由器上的客户端全部强制退出重新登录。当用户再次登录时,会连接到假冒的路由器上,弹出登录窗口,并要求用户输入无线网络的用户名和密码来更新路由器硬件,从而盗取用户的账号密码等信息。
防护方法:
1.不连接公共场所的wifi,重要文件用手机热点发送
2.路由器定期更换密码
3.路由器定期升级

8. 挖矿木马

由于区块链技术热炒以及数字货币的推广运营,如比特币、以太币等层出不穷的数字货币各种热炒,在这些的利益驱使下便出现各种模式的挖矿木马程序,挖矿木马主要就是通过利用各种手段,将挖矿程序植入到用户的计算机中,在用户不知情的情况下,偷偷利用用户的计算机进行执行挖矿功能,从而获取收益。
用户中木马的常见方式:
1.用户往往在不注意的时候,下载并运行了来历不明的破解软件或不安全软件
2.用户点击运行了钓鱼邮件中的附件的文件
3.用户没有做好系统及时更新,通过系统漏洞传播
4.用户浏览了植入挖矿脚本的网页,浏览器就解析脚本进行挖矿
防护方法:
1.在计算机中安装病毒查杀软件(火绒、360杀毒),并及时更新病毒查杀软件的病毒库,还需做好定时全盘查杀病毒。
2.及时做好计算机系统补丁的更新。
3.服务器、主机、数据库等使用高强度的密码口令,切勿使用弱口令,防止被暴力破解。
4.网络上不要去随意下载、运行来历不明的程序或者破解程序,不随意点击来历不明的链接。

9. 0day攻击

0day漏洞是指攻击者最新发现的,厂家还未发布补丁,在网络上还未公布的系统或应用程序新漏洞。
防护方法:
1.安装实时监控和主动防御设备
2.实施网络边界防范
3.加固终端系统
4.加强网络基础设施的安全


博客地址:http://xiejava.ishareread.com/


“fullbug”微信公众号

关注:微信公众号,一起学习成长!

<123…20>
XieJava

XieJava

200 日志
11 分类
25 标签
RSS
GitHub
友情链接
  • 爱分享读书
  • CSDN
  • 豆瓣
© 2025 XieJava | Site words total count: 415.3k

主题 — NexT.Muse
0%