基于阿里云函数计算实现OSS文件自动索引功能

前言

可能是我的搜索方式不对。总之,我找不到OSS自动索引当前目录文件的功能。所以,决定自己写一个,操作并不难。

首先要有一个美观的索引页面,为了锻炼一下自己,就用bootstrap手写了一个,效果如下:

001

使用

因为是使用的阿里云函数计算,所以要先开通服务
新建函数 - 事件函数
002

所在服务,函数名称:随便取一个名
运行环境:python3 (因为我是用Python写的)
函数入口:index.handler(代表OSS事件发生后,会调用index.py里的handler函数)
函数执行内存:选一个最小的就够用了

003

在代码执行中直接粘贴下面的代码
004

index.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
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
import oss2
import json
import datetime
import pytz # 时区

tz = pytz.timezone('Asia/Shanghai') # +8时区
auth = oss2.Auth('<你的阿里云AccessKey>', '<你的阿里云AccessKeySecret>')
endpoint = 'oss-cn-hongkong-internal.aliyuncs.com'
#endpoint = 'oss-cn-hongkong.aliyuncs.com'
bucketName = '<你的bucketName>'
bucket = oss2.Bucket(auth, endpoint, bucketName)
#返回给云函数的信息
message = ""

# 列举Object大小
def objsize(obj):
dict = {0: 'B', 1: 'KB', 2: 'MB', 3: 'GB'}
size = obj.size
cnt = 0
while (size / 1024 >= 1 and cnt < 3):
size /= 1024
cnt += 1
return str(round(size, 2)) + dict[cnt]


# 列举Object最后修改时间
def objtime(obj):
timestamp = obj.last_modified
time = datetime.datetime.fromtimestamp(timestamp, tz)
return time.strftime("%Y-%m-%d %H:%M:%S")


# 写某一个Object的链接
def writeitem(obj, folder):
# 当前Object不是首页和当前目录
if (len(folder) != len(obj.key) and obj.key.find('index.html') == -1):
# Object是目录
if (obj.is_prefix()):
return "<tr><td><a href='/" + obj.key + "'>" + obj.key[len(folder):] + "</a></td><td></td><td></td></tr>"
else:
return "<tr><td><a href='/" + obj.key + "'>" + obj.key[len(folder):] + "</a></td><td>" + objsize(
obj) + "</td><td>" + objtime(obj) + "</td></tr>\n"
else:
return ""


# 列举folder目录下所有文件和子目录。flag:是否递归
def dfs(folder, flag):
global message
# index.html头部信息
html = "<!DOCTYPE html><html><head><meta http-equiv=\"content-type\" content=\"txt/html; charset=utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css\"><title>Index of /" + folder + "</title></head><body><div class=\"container\"><div class=\"row\"><h1>Index of /" + folder + "</h1><hr><table class=\"table table-striped table-hover\"><thead><tr><th>File name</th><th>File Size</th><th>Date</th></tr></thead><tbody>"
# 首页不需要返回上一层
if (folder != ''):
html += "<tr><td><a href='../'>../</a></td><td></td><td></td></tr>\n"
# 列举文件夹
for obj in oss2.ObjectIterator(bucket, prefix=folder, delimiter='/'):
if obj.is_prefix():
html += writeitem(obj, folder)
# message += 'directory: ' + obj.key+'\n'
# 列举文件
for obj in oss2.ObjectIterator(bucket, prefix=folder, delimiter='/'):
if not obj.is_prefix():
html += writeitem(obj, folder)
# message += 'file:' + obj.key+'\n'
# index.html尾部信息
html += "</table><hr></div></div></body></html>"
# 上传index.html的地址
url = folder + "index.html"
# 上传index文件
result = bucket.put_object(url, html)
# print(html)
message += 'Url:{0}'.format(url) + '\n'
message += 'HTTP status: {0}'.format(result.status) + '\n'
# 递归操作
if (flag):
for obj in oss2.ObjectIterator(bucket, prefix=folder, delimiter='/'):
if obj.is_prefix(): # 文件夹
dfs(obj.key, flag)


# OSS有创建删除Object事件产生
def handler(event, context):
result = bucket.head_object('event.txt')
bucket.append_object('event.txt',result.content_length,event)
global message
message = ""
eventObj = json.loads(event)["events"]
url = eventObj[0]['oss']['object']['key']
eventName = eventObj[0]['eventName']
# 得到事件发生Object的URL
if (url.find('index.html') == -1):
# 不是index.html
if (len(url) - 1 == url.rfind('/')):
# 如果是创建修改目录,当前目录需要更新
dfs(url,False)
# 同时目录的上层目录需要更新
url = url[:-1]
if (url.find('/') == -1):
dfs(folder='', flag=False)
else:
dfs(url[:url.rfind('/') + 1], False)
return message
else:
return 'Not Modified'

可以在触发事件中选一个OSS模板的测试事件

005

执行结果类似这样

006

然后在创建一个OSS的触发器,中间可能会要求授予调用的权限,按照提示操作即可

007

费用

阿里云函数计算每个月每个账户有一定的免费额度,所以正常使用免费。

OSS费用按照OSS的收费方式进行。