在使用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是有区别的。

联系作者

在编写单元测试时,每次重新创建MySQL数据库表都花费很长时间,于是在表结果不变的情况下,想使用keepdb参数,即执行
python manage.py test --keepdb, 会报如下错误

1
2
Using existing test database for alias 'default'...
Got an error creating the test database: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE DATABASE IF NOT EXISTS `test_tdcmdb` CHARACTER SET utf8mb4;\n ' at line 2")

查找错误来源,在django.db.backends.mysql.creation.py里的_execute_create_test_db函数中,

1
2
3
4
5
cursor.execute('''
SET @_tmp_sql_notes := @@sql_notes, sql_notes = 0;
CREATE DATABASE IF NOT EXISTS %(dbname)s %(suffix)s;
SET sql_notes = @_tmp_sql_notes;
''' % parameters)

改成

1
2
3
cursor.execute('''
CREATE DATABASE IF NOT EXISTS %(dbname)s %(suffix)s;
''' % parameters)

后,问题得到解决。

联系作者

最近公司开始使用Gerrit做code review工具,于是才知道git pull还有rebase这个参数。

当本地分支commit后,然后git pull拉取远程分支的提交,之后使用git review生成一个review时,会提示有多个提交。于是想到git rebase, 但是没想到的是git pull也有rebase参数。

洁癖者用 Git:pull –rebase 和 merge –no-ff里提到了pull –rebase的妙用,解决了多年的困惑。之前使用git pull时,老是生成很多无效的merge, 没想到使用git pull –rebase可以解决这个问题

联系作者

Celery定时任务里介绍,配置定时任务使用crontab, 并设置timezone。于是配置了timezone=”Asia/Shanghai”, 然而时间总是偏差8个小时,在Cannot use local time for cron schedules and UTC for solar schedules里找到解决的办法。原来问题的根源是Celery里的now函数定义出错了。查看now函数的实现

1
2
3
4
def now(self):
"""Return the current time and date as a datetime."""
from datetime import datetime
return datetime.utcnow().replace(tzinfo=self.timezone)

如果写成

1
2
3
4
def now(self):
"""Return the current time and date as a datetime."""
from datetime import datetime
return datetime.now(self.timezone)

就没问题了。
查看datetime.now的实现, 当tz不为空时, datetime.now(tz) 等于tz.fromutc(datetime.utcnow().replace(tzinfo=tz))。所以这是Celery的Bug

但是不能去修改Celery的源码,于是使用评论中提到的解决办法

1
2
3
4
5
6
7
class MyCelery(Celery)
def now(self):
"""Return the current time and date as a datetime."""
from datetime import datetime
return datetime.now(self.timezone)

app = MyCelery()

联系作者

自从买了1Password后,减轻了记密码的负担,整个人轻松了不少。

在浏览器上输密码时,可以使用Option + Command + \来弹出密码选项,之后搜索需要的密码,敲回车就可以登录。

但在item这种终端中,一直不知道如何输密码。看同事用了一次,才知道诀窍。在终端中,也是使用Option + Command + \来弹出密码选项,之后搜索需要的密码,然后用Shift + Command + C来复制密码,用Command + V来粘贴密码登录。

联系作者

之前线上跑的Celery出现了堵塞,导致任务无法执行。这次抽空找找原因。

堵塞的时候,从flower上看到很多任务都处于started状态,而started状态的任务数量正好等于celery进程数。

同样提交大量上次执行的任务,Celery又堵塞了。查看执行的任务,没发现有什么特别的,唯一的问题是任务里再套了一个Celery异步任务,并需要获取到执行的结果。

仔细分析,问题就出在这里。当提交大量的这种任务时,把Celery进程都占满了,然而这些任务都需要另起一个Celery任务才能执行完,此时已经没有Celery进程可以使用,于是所有的任务都无法执行。

解决的办法是,Celery任务里不要再起Celery异步任务, 如果非要这样做,避免大量出现这样的任务。

后来,同事的Celery也出现了堵塞,与他一起查找,没发现问题。于是请教另一位同事,他用pstree命令和strace命令把问题的原因找到。

联系作者

在用Vue写前端时,看到同事写的代码里

1
2
this.subnetIps[String(subnet_id)] = ''
this.subnetIps[String(subnet_id)] = ips

觉得很奇怪,为什么要先置空,再赋值?尝试把this.subnetIps[String(subnet_id)] = ''去掉后,发现前端的值不会发生变化。于是看Vue文档,在检测变化的注意事项里提到这是由于Javascript语言的缺陷造成的。文档里提到可以使用$set方法,于是把两条语句改成this.$set(this.subnetIps, String(subnet_id), ips)

联系作者

最近线上生产环境出了一次故障,大量机器出现大量僵死进程,导致服务僵死。部门里组织同事小黑屋查找原因,找了大半天终于找到原因,罪魁祸首竟然是安全部门的漏洞扫描。

刚开始的时候,发现机器上有大量Salt minion进程,以为是Salt的原因。后来以为同事发现这些僵尸进程的父进程都是init进程,而init进程处于T(stopped)状态,所以这些僵尸进程都没法回收,导致大量僵尸进程堆积。同事还推荐使用kill -SIGCONT pid恢复进程状态。

接下来就是要找到使init变成T状态的根源,经过排查,终于锁定使安全部门的漏洞扫描。按常理,正常的扫描应该是可以反复执行,不会对系统造成干扰。但安全部门新增加的扫描插件却会发送stop信号给init进程,而在CentOS 6.6上,init进程响应了这个信号,于是进入stopped状态。于是init无法回收僵尸进程,导致僵尸进程越来越多。

联系作者