想对show processlist命令的结果进行过滤,分组操作,不支持。在The INFORMATION_SCHEMA PROCESSLIST Table里可以看到SHOW FULL PROCESSLIST 和 SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST效果是相等的,于是可以在PROCESSLIST表上进行过滤分组操作。

  • 需要对host进行统计 select substring_index(host,’:’ ,1) as server, count(*) from information_schema.processlist group by server;
  • 查询执行时间超过2分钟的线程,然后拼接成 kill 语句 select concat(‘kill ‘, id, ‘;’) from information_schema.processlist where command != ‘Sleep’ and time > 2*60 order by time desc

参考资料

在安装Python包时,报如下错误

1
2
3
4
from Crypto.PublicKey import RSA
from Crypto.Util.asn1 import (DerSequence, DerInteger, DerBitString,

ImportError: cannot import name 'DerBitString' from 'Crypto.Util.asn1'

在网上只找到ImportError: cannot import name ‘DerBitString’, 评论里说 Could you please try in a new virtualenv? It seems related to your virtualenv.

我使用的是pyenv搭建的Python3.6.2, 报错, 后来同事用virtualenv搭了个Python3.7.0的环境,不会报错。于是试了用pyenv搭建个Python3.7.0的环境,还是报错。于是可以确定是pyenv的原因,用virtualenvwarpper搭了个Python3.6.5的环境,这次没有报错。

用了这么久pyenv, 第一次遇到这种问题,莫名奇妙。

2018年11月23日更新: 发现原因了,是因为PyCrypto包和PyCryptodome有冲突,当只安装PyCrypto时就没有这个问题。事实上,最好使用PyCryptodome这个包,因为它是PyCrypto的替代者,只是这里应用依赖PyCrypto包,所以才用它。

有些时候,需要用到嵌套过滤,例如如果要求数据都只是逻辑删除时,此时就会用到。例如有一个应用表,还有一个应用成员表, 如果显示应用详情时,想在一个接口把应用成员一起显示出来,此时就需要过滤掉那些被逻辑删除的成员。

如下定义的application和member

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Application(models.Model):
"""应用"""

name = models.CharField(max_length=32, help_text='应用名称')
is_deleted = models.BooleanField(default=False, help_text='是否已删除')
gmt_create = models.DateTimeField(auto_now_add=True)
gmt_modify = models.DateTimeField(auto_now=True)

class Member(models.Model):
"""应用成员"""

application = models.ForeignKey(Application, help_text='应用', related_name='members', on_delete=models.PROTECT, db_constraint=False)
user = models.ForeignKey(User, help_text='成员', on_delete=models.PROTECT, db_constraint=False)
is_deleted = models.BooleanField(default=False, help_text='是否已删除')
gmt_create = models.DateTimeField(auto_now_add=True)
gmt_modify = models.DateTimeField(auto_now=True)

序列化如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class MemberSerializer(Serializer):
'''应用成员 序列化器'''

class Meta:
model = Member
fields = '__all__'
read_only_fields = ('gmt_create', 'gmt_modify', 'is_deleted')


class ApplicationDetailSerializer(Serializer):
members = MemberSerializer(many=True)

class Meta:
model = Application
fields = '__all__'
read_only_fields = ('gmt_create', 'gmt_modify', 'is_deleted')

此时会把应用中逻辑删除掉的用户也查出来,查看How do you filter a nested serializer in Django Rest Framework?得到解答。需要在Meta中添加list_serializer_class, 修改后如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class DeletedFilterListSerializer(ListSerializer):

def to_representation(self, data):
data = data.filter(is_deleted=False)
return super(DeletedFilterListSerializer, self).to_representation(data)


class MemberSerializer(Serializer):
'''应用成员 序列化器'''

class Meta:
list_serializer_class = DeletedFilterListSerializer
model = Member
fields = '__all__'
read_only_fields = ('gmt_create', 'gmt_modify', 'is_deleted')

如此序列化应用时,就不会把删除掉的应用成员查出来

有时候在命令行看到一个html文件,就想在浏览器中打开看看是什么。

此时要么在Finder里找到文件打开,或者在浏览器中用file:// + 文件绝对路径。但总觉得不够好。

今天上午搜索之后,发现Mac下有open命令

于是可以用open -a safari 文件名, 或者也可以用open -a Google\ Chrome 文件名打开

故事还没完,在我向同事展示学习到的黑科技时,同事给出了一种更高效的打开方式,按住Command, 点击文件。

之前同事发来一个邮箱匹配的正则表达式,^([a-z0-9A-Z]+[-|\\.|_]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$,说匹配的时候会卡住, 测试一下re.match("^([a-z0-9A-Z]+[-|\\.|_]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$", "sdfwerwerwerwerwsdfsdfsdfsdfsdfsdf"), 果然卡死 。找了很久没发现原因,后来看到浅析ReDoS的原理与实践后,才恍然大悟。([a-z0-9A-Z]+[-|\\.|_]?)+就是(a+)+这种形式, 而(a+)+这种类型的正则匹配时回溯次数特别多,很容易引起正则攻击.

类似的正则有

  • (a+)+
  • ([a-zA-Z]+)*
  • (a|aa)+
  • (a|a?)+
  • (.*a){x} for x > 10

查看《正则指引》,书中给了一个Python版本的正则表达式。r'^(?!\.)(?![\w.]*?\.\.)[\w.]{1,64}@(?=[-a-zA-Z0-9.]{0,255}(?![-a-zA-Z0-9.]))((?!-)[-a-zA-Z0-9]{1,63}\.)*(?!-)[-a-zA-Z0-9]{1,63}$'

其中@之前的部分是用户名,其长度不超过64个字符,所以是[\w.]{1,64}, 用户名不能以点号开头,所以添加环视(?!.), 同时用户名不能包含连续点号, 所以需要添加环视(?![\w.]*?\.\.)

@后面的部分是主机名,主机名分为很多段,每段长度不超过63,所以是[-a-zA-Z0-9]{1,63}, 且每段不能以横线开头,这一点用环视(?!-)保证,总长度不能超过255,用(?=[-a-zA-Z0-9.]{0,255}(?![-a-zA-Z0-9.]))来保证。主机名可以看做是”段+点号”的重复,所以是((?!-)[-a-zA-Z0-9]{1,63}\.)*, 最后的段必须出现,所以再添加一个(?!-)[-a-zA-Z0-9]{1,63}

看到晚上很多错误的例子,https://blog.csdn.net/xxm282828/article/details/43549959https://blog.csdn.net/bug_love/article/details/78799277https://www.oschina.net/code/snippet_1021818_47946,抄来抄去,都是错的。

同事发了下面一个错误, 让我复现并找到解决的办法。错误原因是www.example.com的前端页面访问后端api.example.com出错。

1
2
3
4
5
{
"detail":"CSRF Failed: Referer checking failed -
https://www.example.com/ does not match any trusted origins."

}

CSRF validation does not work on Django using HTTPS中找到类似的错误,但是不知道怎么复现,在Issue with CsrfViewMiddleware and “referer” same_origin checking for secure (https) subdomains中发现有可能是CsrfViewMiddleware检测的原因。

于是才想起来可以用将”does not match any trusted origins”放到Django源码中搜索下,果然是在CsrfViewMiddleware里,于是将一些代码注释掉,知道在settings里配置一下CSRF_TRUSTED_ORIGINS即可,于是添加CSRF_TRUSTED_ORIGINS = [‘example.com’], 问题解决。

整个解决过程现在回想起来有些浪费时间,最有效的方法还是拿关键字到源码中找到对应代码,看看报错原因。

实现文章列表时,写了如下组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const axios = require('axios');
var ComponentBlog = {
props: ['post'],
template: `
<div class="blog-post">
<h3>{{ post.title }}</h3>

<div v-html="post.content"></div>
</div>
`
}
export default {
components: {
'blog-post': ComponentBlog
},

但是希望组件能够在其它页面复用,于是放在一个文件中,然后导入进来。在这里,我放在BlogPost.vue中,文件内容如下

1
2
3
4
5
6
<template>
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
</template>

然后编写如下代码使用组件

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
<template>
<div>
<blog-post v-for="post in posts" :key="post.id" :post="post"></blog-post>
</div>
</template>

<script>
import BlogPost from '@/components/BlogPost'
const axios = require('axios');
export default {
components: {
BlogPost
},
data () {
return {
posts: [],
}
},
created() {
this.fetchPost();
},
methods: {
fetchPost() {
axios.get('http://127.0.0.1:7001/api/blog/posts/')
.then(response => {
console.log(response)
console.log(this)
this.posts = response.data.results
})
.catch(error => {
// handle error
console.log(error);
})
}
}
}
</script>

但是一直报post是未定义的。问过同事后,才知道在Vue文档中,有介绍单文件组件的使用方法。于是将BlogPost.vue改成如下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div class="blog-post">
<h3>{{ post.title }}</h3>
<div v-html="post.content"></div>
</div>
</template>

<script type="text/javascript">

export default{
props: {
post: Object
},
data(){
return {
}
},
created(){
},
methods: {
},
}
</script>

这样之后,组件就可以正常使用了。

在使用vue-router时,URL中总会有多了个#, 看着总是不爽,而且多了这个符号,以前被搜索引擎收录的页面就无法访问了,于是想办法去除。在Vue的文档中HTML5 History 模式找到了解答,也就是添加history模式即可。

1
2
3
4
const router = new VueRouter({
mode: 'history',
routes: [...]
})

看到警告中说,这么做以后,服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,你应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面。

1
2
3
4
5
6
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})

在使用axios来进行Ajax请求时遇到这个问题。

使用如下代码向后端API请求时,无法对posts赋值,this是undefined

1
2
3
4
5
6
7
8
9
10
11
12
fetchPost() {
axios.get('http://127.0.0.1:7001/api/blog/posts/')
.then(function (response) {
console.log(response);
console.log(this);
this.posts = response.data.results
})
.catch(error => {
// handle error
console.log(error);
})
}

于是改成Vue教程中使用 axios 访问 API的箭头函数,这次可以得到结果。

1
2
3
4
5
6
7
8
9
10
11
12
fetchPost() {
axios.get('http://127.0.0.1:7001/api/blog/posts/')
.then(response => {
console.log(response);
console.log(this);
this.posts = response.data.results
})
.catch(error => {
// handle error
console.log(error);
})
}

深入浅出ES6(七):箭头函数 Arrow Functions里写到,普通function函数和箭头函数的行为有一个微妙的区别,箭头函数没有它自己的this值,箭头函数内的this值继承自外围作用域。原来如此。

决定把自留地的前端代码独立开来,决定使用Vue来做。从0开始,遇到各种问题,打算记下来。最新遇到跨域问题,在访问服务的API时,报如下错误 No ‘Access-Control-Allow-Origin’ header is present on the requested resource,知道是跨域问题。看阮一峰跨域资源共享 CORS 详解,知道跨域是怎么回事。

以前就知道Dango有django-cors-headers模块用来支持跨域, 只是没有自己配置过。按照文档进行配置,加上白名单

1
2
3
CORS_ORIGIN_WHITELIST = (
'127.0.0.1:8081',
)

发现还是报相同的错误,改成

1
2
3
4
CORS_ORIGIN_WHITELIST = (
'127.0.0.1:8081',
'localhost:8081',
)

后就没有这个问题了。说明localhost和127.0.0.1是有区别的。