koa2实现上传图片,并且同步上传到七牛云存储

因为升级到新的node版本,之前的通过很多上传图片的方式都已经不适用了,所以自己就写了一个对于 koa2上传图片的小demo,记录一下心得。

废话不多说,下面直接上代码,里面都有注释。

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
131
132
133
134
135
136
137
138
139
const Koa = require('koa');
const route = require('koa-route');
const serve = require('koa-static');
const inspect = require('util').inspect
const path = require('path')
const os = require('os')
const fs = require('fs')
const Busboy = require('busboy')
const qiniu = require('qiniu')
const qiniuConfig = require('./qiniuconfig')
const app = new Koa();
app.use(serve(__dirname + '/public/'));
// 写入目录
const mkdirsSync = (dirname) => {
if (fs.existsSync(dirname)) {
return true
} else {
if (mkdirsSync(path.dirname(dirname))) {
fs.mkdirSync(dirname)
return true
}
}
return false
}
function getSuffix (fileName) {
return fileName.split('.').pop()
}
// 重命名
function Rename (fileName) {
return Math.random().toString(16).substr(2) + '.' + getSuffix(fileName)
}
// 删除文件
function removeTemImage (path) {
fs.unlink(path, (err) => {
if (err) {
throw err
}
})
}
// 上传到七牛
function upToQiniu (filePath, key) {
const accessKey = qiniuConfig.accessKey // 你的七牛的accessKey
const secretKey = qiniuConfig.secretKey // 你的七牛的secretKey
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
const options = {
scope: qiniuConfig.scope // 你的七牛存储对象
}
const putPolicy = new qiniu.rs.PutPolicy(options)
const uploadToken = putPolicy.uploadToken(mac)
const config = new qiniu.conf.Config()
// 空间对应的机房
config.zone = qiniu.zone.Zone_z2
const localFile = filePath
const formUploader = new qiniu.form_up.FormUploader(config)
const putExtra = new qiniu.form_up.PutExtra()
// 文件上传
return new Promise((resolved, reject) => {
formUploader.putFile(uploadToken, key, localFile, putExtra, function (respErr, respBody, respInfo) {
if (respErr) {
reject(respErr)
}
if (respInfo.statusCode == 200) {
resolved(respBody)
} else {
resolved(respBody)
}
})
})
}
// 上传到本地服务器
function uploadFile (ctx, options) {
const _emmiter = new Busboy({headers: ctx.req.headers})
const fileType = options.fileType
const filePath = path.join(options.path, fileType)
const confirm = mkdirsSync(filePath)
if (!confirm) {
return
}
console.log('start uploading...')
return new Promise((resolve, reject) => {
_emmiter.on('file', function (fieldname, file, filename, encoding, mimetype) {
const fileName = Rename(filename)
const saveTo = path.join(path.join(filePath, fileName))
file.pipe(fs.createWriteStream(saveTo))
file.on('end', function () {
resolve({
imgPath: `/${fileType}/${fileName}`,
imgKey: fileName
})
})
})
_emmiter.on('finish', function () {
console.log('finished...')
})
_emmiter.on('error', function (err) {
console.log('err...')
reject(err)
})
ctx.req.pipe(_emmiter)
})
}
app.use(route.post('/upload', async function(ctx, next) {
const serverPath = path.join(__dirname, './uploads/')
// 获取上存图片
const result = await uploadFile(ctx, {
fileType: 'album',
path: serverPath
})
const imgPath = path.join(serverPath, result.imgPath)
// 上传到七牛
const qiniu = await upToQiniu(imgPath, result.imgKey)
// 上存到七牛之后 删除原来的缓存图片
removeTemImage(imgPath)
ctx.body = {
imgUrl: `http://xxxxx(你的外链或者解析后七牛的路径)/${qiniu.key}`
}
}));
app.listen(3001);
console.log('listening on port 3001');

然后在同一级目录下,创建一个public文件夹,然后在下面新建一个 index.html,因为我们上面已经把这个文件夹设置为静态访问文件夹了, public/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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input id="btn1" type="file" name="file"/>
<input id="btn2" type="submit" value="提交"/>
</body>
<script>
var btn1 = document.querySelector('#btn1')
var btn2 = document.querySelector('#btn2')
var file = null
btn1.addEventListener('change', function(e){
file = e.target.files[0]
})
btn2.onclick = function(){
var _data = new FormData();
_data.append('file', file);
xhr(_data)
}
var xhr = function(formdata){
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("post","http://127.0.0.1:3001/upload", true);
xmlHttp.send(formdata);
xmlHttp.onreadystatechange = function(){
if(xmlHttp.readyState==4){
if(xmlHttp.status==200){
var data = xmlHttp.responseText;
console.log(data);
}
}
}
}
</script>
</html>

选择好图片,然后点击提交,就可以上传到你的七牛空间啦!

文章博客地址: http://blog.naice.me/articles

ps: 如果对你有帮助请随手丢一个 start 哦

源代码在 github: https://github.com/naihe138/koa-upload

js IOS/Iphone,微信端不兼容 Date()的问题

1
2
var date = new Date('2016-11-11 11:11:11');
document.write(date);

IE跟safari都不兼容,返回错误”Invalid Date”。

iPhone中的safari无法解释 YYYY-MM-DD HH:mm:ss 或者YYYY/MM/DD HH:mm:ss这样的时间格式,而谷歌火狐等浏览器对这样的格式做了扩展,iPhone中的safari所支持的格式为 YYYY,MM, DD,HH,mm,ss;

绞尽脑汁,最后还是在论坛上看到了这样一种解决方案:

1
2
3
var arr = "2016/11/11 11:11:11".split(/[- : \/]/),
date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);
document.write(date);

react、react-router、redux 也许是最佳小实践2

上一篇:react、react-router、redux 也许是最佳小实践1

加入 redux

React 在组件之间流通数据.更确切的说,这被叫做“单向数据流”——数据沿着一个方向从父组件流到子组件。由于这个特性,对于没有父子关系的两个组件之间的数据交流就变得不是那么显而易见。这里 Redux 就排上用场了。Redux提供了一个解决方案,通过将应用程序所有的状态都存储在一个地方,叫做“store”。然后组件就可以“dispatch”状态的改变给这个store,而不是直接跟另外的组件交流。所有的组件都应该意识到状态的改变可以“subscribe”给store。如下图:
Alt text

react、react-router、redux 也许是最佳小实践1

小前言

这是一个小小的有关react的小例子,希望通过一个小例子,可以更好的了解到react、react-router4.0、redux的集中使用方法。

  1. 这是基于create-react-app来开发的,一种简单的快速创建 React web 项目的方式是使用 Create React App 工具,相当于一个react手脚架,此工具由 Facebook 开发并维护。如果你还没有使用过 create-react-app,你需要先安装。然后就可以通过它创建一个新项目。
  2. React Router4.0 号称一次学习,随处路由。通过声明式编程模型定义组件,是 React 最强大的核心功能。 React Router 可以为您的应用已声明式的方式定义导航组件最强大的核心功能。 无论是 Web App 的浏览器书签 URLs,还是 React Native 的导航功能, 只要是可以使用 React 的地方,就可以使用 React Router
  3. Redux 是一个用来管理JavaScript应用中 data-state(数据状态)和UI-state(UI状态)的工具,对于那些随着时间推移状态管理变得越来越复杂的单页面应用(SPAs)它是比较理想。阮老师redux的教程

下面我们看看完成后的小 demo

react-plan

浅谈ajax原理过程以及实现

1.什么是AJAX?

AJAX全称为“Asynchronous JavaScript and XML”(异步JavaScript和XML),是一种创建交互式网页应用的网页开发技术。它使用:

  1. 使用XHTML+CSS来标准化呈现;
  2. 使用XML和XSLT进行数据交换及相关操作;
  3. 使用XMLHttpRequest对象与Web服务器进行异步数据通信;
  4. 使用Javascript操作Document Object Model进行动态显示及交互;
  5. 使用JavaScript绑定和处理所有数据。

    2.AJAX的工作原理

    Ajax的工作原理相当于在用户和服务器之间加了—个中间层(AJAX引擎),使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器,像—些数据验证和数据处理等都交给Ajax引擎自己来做, 只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
    Ajax:Asynchronous javascript and xml,实现了客户端与服务器进行数据交流过程。使用技术的好处是:不用页面刷新,并且在等待页面传输数据的同时可以进行其他操作。

基于react+bootstrap+koa2开发的“微说说”

其实很久都想学学react以及koa了,最近就想到一个小例子,用来练练手,就写了一个微说说,项目地址:https://github.com/naihe138/micro-zone

####基本的需求其实很简单,也就5个小功能:

  1. 登录
  2. 注册
  3. 发表微说说
  4. 对微说说进行评论
  5. 可以相互评论

前端:是用bootstrap-webpack这个模块让reactbootstrap交给webpack打包,其中还有基本的路由跳转

后端:使用koa2mongoose进行接口的模块开发,主要是练习koa2框架的写法,以及用moongose对数据库的增删改查,包括联表查询。

javascriipt进制之间的转换二进制,8进制,10进制,16进制之间的转换

在公司,碰到生成设备指令的问题?需要做个16、10、2进制之间的转换,再次特意做一个笔记。在这里会详细的介绍一下Javascript中的Number的toString,以及parseInt()的方法。

在js中数字(Number)的toString方法

Number 类型的 toString() 方法比较特殊,它有两种模式,即默认模式和基模式。采用默认模式,toString() 方法只是用相应的字符串输出数字值(无论是整数、浮点数还是科学计数法),如下所示:

1
2
3
4
var iNum1 = 10;
var iNum2 = 10.0;
alert(iNum1.toString()); //输出 "10"
alert(iNum2.toString()); //输出 "10"

注释:在默认模式中,无论最初采用什么表示法声明数字,Number 类型的 toString() 方法返回的都是数字的十进制表示。因此,以八进制或十六进制字面量形式声明的数字输出的都是十进制形式的。

|