文件管理服务 JFile¶
简介¶
文件管理服务 JFile 基于公有云的对象存储,提供海量、安全、高可靠和低成本的云存储服务。用户可以通过 JFile 上传文件,并且上传的文件可以在其它任意 Jarvis 系统中被使用。JFile 完成应用和公有云存储之前的转发,后续提供简单的云文件管理功能。
相比传统的文件存储,JFile 有以下优点:
易用性,支持 RESTful API 和多版本 SDK 等方式接入;
高可靠,实现文件多节点备份,文件持久性不低于 99.999999999%;
低成本,相比自建存储降低 25%-75% 的成本,且存储容量无限制;
速度快,基于公有云存储,提供 CDN 下载链接,使文件传输更快、更稳定;
应用场景¶
图片和音视频等应用的海量存储¶
JFile 可用于图片、音视频、日志、excel、word 等海量文件的存储。 各种终端设备、web 网站程序、移动应用可以直接向 JFile 写入或读取数据。并且提供安全的文件加密方式,特别适合云上应用接入。
应用案例

常见问题¶
文件流¶
上传的文件以文件流的形式上传。
文件名¶
如果需要文件名不变,设置 random_name = 0。random_name = 1 生成随机文件名。
重名文件¶
每个用户都有自己的存储空间,用户只可以上传到自己的存储空间中,不会与其他用户的文件冲突。
如果上传时设置了 random_name = 0,保存时按照用户上传的文件名进行保存,当再次上传相同文件名的文件时则默认会覆盖原有的文件,每次覆盖之后返回的 file_token 都相同;可以设置 overwrite=0 来禁止 Jarvis File 覆盖已存在的文件,如果发生文件重名则会返回 400 错误。
自定义 file_token¶
在上传时可以指定自定义的 filetoken(customfiletoken),用户可以使用该自定义的 filetoken 进行下载和删除。
当下载其他用户自定义的 filetoken 时必须指定对方的 apptoken (belongapptoken),否则只会下载自己自定义的 file_token。
自定义 filetoken 只是一个别名,实际上传后 Jarvis File 还会返回真实的 filetoken,同样可以使用返回的 filetoken 进行下载和删除,请尽量避免使用 Jarvis File 的 filetoken 命名规则,否则可能会造成 file_token 冲突而导致文件不能被下载。
版本控制¶
Jarvis File 采用 API 路由中传递版本号(例如:/file/v6/files 或 /file/v6/files),调用不同的 Jarvis File 的版本实现不同的上传/下载方式,调用不同版本的 Jarvis File 上传都不会改变文件的存储方式,请放心使用任意版本进行下载。
文件安全性¶
有两种方式保证文件安全:
设置文件有效期,private = “1”,为私有文件,默认有效期 600s
通过设置将文件加密,encryption = “1”
帮助¶
Jarvis File 提供了测试/生产环境的测试页面( http://jua.huifutest.com/file/v6/web/index.html, https://jua.cloudpnr.com/file/v6/web/index.html) 可以方便的文件上传/下载/删除,同时也可以使用该测试页面获取和设置共享用户。
使用测试页面需要注意尽量避免使用低版本的浏览器或 IE 浏览器,测试页面提交的 apptoken 及 appkey 存储于浏览器的缓存中,请及时清理缓存以免泄漏 app_key。
白名单¶
Jarvis File 对不同安全级别的文件采用了不同的方式对文件进行存储,会导致在文件下载时返回不固定的域名。 默认返回外网地址,请确保以下外网地址设置成白名单:
API 文档¶
账号申请(app_token、app_key)¶
账号申请流程,即 BUser 申请,请见章节 “BUser申请流程”
请求地址¶
生产外网地址:https://jua.cloudpnr.com
生产内网地址:http://jua.hfinside.com
公共参数¶
公共请求参数
除了下载密码保护文件接口,其它接口都有以下请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
app_token |
String |
是 |
应用 app_token |
|
signature |
String |
是 |
signature 注:明文拼接规则第2条除外,请求地址不参与明文拼接,具体生成方式请参考”API签名” |
参数校验错误返回码
返回码 返回信息
30013 param exist empty - 参数为空
30014 param type error - 参数类型错误
30015 param length error - 参数长度错误
上传文件¶
使用 JFile 上传的文件存储在云端后,会自动将文件复制到多个不同的节点进行存储,确保文件不会丢失。
根据使用用途文件分为 3种 文件:
公共文件,上传的文件可以在任何时间任何地点下载,并且对文件提供了 cdn 加速服务。设置参数 private = “0”;
普通的私有文件,文件下载地址有效期,默认有效期 600s;
加密的私有文件,上传的文件由系统加密机进行加密存储,保证文件的安全性。设置参数 encryption = “1”;
HTTP Request
POST http://jua.huifutest.com/file/v6/files
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
files |
文件 |
是 |
上传的文件 |
|
timestamp |
String |
是 |
10 位或 13 位,两次提交不能重复 |
时间戳 |
encryption |
String |
否 |
“1” 或 “0”,默认为 “0” |
是否加密存储,”1” 表示文件加密存储 ,”0” 表示文件不加密存储 |
is_cdn |
String |
否 |
“1” 或 “0”,默认为 “0” |
是否开启CDN加速,”1” 表示开启 ,”0” 表示不开启。需频繁下载的资源文件建议开启,开启后可避免产生较大的费用(private 必须为0,否则不生效) |
private |
String |
否 |
“1” 或 “0”,默认为 “1” |
是否是私有文件,”1” 表示私有文件,下载地址有有效期限制(有效期默认值600s) ,”0”表示公有文件,下载地址无有效期限制 ,注:公有文件无需加密 |
path |
String |
否 |
小于等于 200 个字节 |
保存的路径 |
random_name |
String |
否 |
“1” 或 “0”,默认值为 “1” |
文件名是否随机 ,”1” 表示文件上传后文件名随机 ,”0”表示文件上传后文件名不变,相同的文件名会覆盖原有的文件 |
over_write |
String |
否 |
“1” 或 “0”,默认值为 “1” |
当random_name 为 “0” 时传递该参数表示是否覆盖文件 ,”1”表示强制覆盖已存在的文件,”0” 表示不覆盖(当出现重名文件时会返回 400错误) |
inside_job |
String |
否 |
“1” 或 “0”,默认值为 “0” |
是否内网用户 ,”1” 表示内网用户,”0” 表示非内网用户,内网用户则会返回*.hfinside.com 内网地址,否则会返回 *.cloudpnr.com 公网地址 |
custom_file_token |
String |
否 |
小于等于 24 个字节 |
自定义 file_token 如果指定的话可以使用自定义的 file_token 进行下载和删除 |
响应参数
名称 |
类型 |
描述 |
---|---|---|
file_token |
String |
上传的文件 ID |
download_url |
String |
文件下载地址(如果是私有文件,文件下载地址使用默认的有效期 600s) |
失败响应
会返回 4xx
或 5xx
,并在响应体中提供一段 JSON
格式的详细错误信息,通用的错误可以参考错误代码章节,使用下表可以查询到
上次文件 API 的错误码。
返回码 返回信息
20203 upload file is too large -上传文件大小超限
30002 sign error - 验签失败,接口 sign 与后台计算结果不一致
30003 save file error -上传文件时,Jarvis 无法保存文件
30006 upload file extension illegal -传递了 Jarvis 不支持的文件扩展名
30007 upload error - 上传文件失败
30008 write file info error -文件信息写库失败,状态码 500
30012 param files is none - 参数 files 为空
30016 param contain special character -文件名包含非法字符
30017 timestamp error - 参数时间戳不为 10 位数字
30019 incorrect signature -签名验签失败
30020 password incorrect - 密码错误
30022 path name illegal -路径名称非法,路径中不能含有特殊 字符
30023 repeated timestamp -相同用户的时间戳重复
30024 unable upload public file with password
-不可以上传带密码的公共文件
30025 random_name must be 1 or 0 -“随机名称” 参数必须是 1 或 0
30026 private must be 1 or 0 -“私有文件” 参数必须是 1 或 0
调用示例
# 创建需要上传的文件
echo 'hello world!' > /tmp/test.txt
curl -X POST \
-F "files=@/tmp/test.txt" \
-F "password=1234567890" \
-F "app_token=app-a8187ae7-5671-4888-4321-2cc8c4d476ba" \
-F "path=/dir1/" \
-F "signature=ce879cded4867fe35d8afa7a08a40e5ac3f8fd80a93da717e9048b2c99840f80" \
http://jua.huifutest.com/file/v6/files
python
import requests
# 创建需要上传的文件
file = open('/tmp/test.txt', 'w')
file.write('hello world!')
file.close()
url = "http://jua.huifutest.com/file/v6/files" # 测试服务器
app_token = "app-a8187ae7-5671-4888-4321-2cc8c4d476ba"
file_info = {
'app_token': app_token,
'password': password,
'path': '/dir1/',
'timestamp': str(int(time.time())),
'private': is_private,
'random_name': is_random_name
} # 拼接请求参数
# 根据参数 key 的值 顺序拼接其 key=value& , 实际做代码操作时, 可以使用排序方法拼接更为合适, 以下只做例子展示
files = open('../test_file/test.txt', 'rb')
encrypt_dict = {
'app_token': file_info['app_token'],
'timestamp': file_info['timestamp'],
'files': md5(files),
'password': file_info['password'],
'path': file_info['path'],
'private': file_info['private'],
'random_name': file_info['random_name']
}
keys = encrypt_dict.keys()
keys = sorted(keys, reverse=False)
# 拼接 key 和 value 值
values = ''
for key in keys:
value = str(encrypt_dict.get(key))
if len(value) == 0:
continue
values = values + '&' + str(key) + '=' + value
plain_text = 'POST' + values[1:]
# 对拼接好的字符串, 以 app_key 作为秘钥进行 hmacsha256 加密处理
file_info['signature'] = hmacsha256(plain_text, app_key)
# 上传文件
response = requests.post(url,
files={'files': files},
data=file_info) # 发送请求
print(response.status_code) # 打印状态码
print(response.text) # 打印返回内容
java
建议,引入 status-file,具体请参考”JAVA-SDK说明”
成功响应
200
{
"file_token": "20f1ee3a-2430-11e7-8e4f-525400792f1a",
"download_url": "......"
}
失败响应
400
{
"message": "incorrect signature",
"return_code": 30019
}
获取文件¶
返回指定 file_token
的文件下载地址或文件内容。
HTTP Request
GET http://jua.huifutest.com/file/v6/files
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
file_token |
String |
是 |
文件 ID |
|
expires |
String |
否 |
有效期 ( 秒 ),默认 600 秒 |
|
inside_job |
String |
否 |
“1” 或 “0”,默认值为 “0” |
是否内网用户 ,”1” 表示内网用户,”0” 表示非内网用户,内网用户则会返回*.hfinside.com 内网文件下载地址,否则会返回 *.cloudpnr.com 公网文件下载地址 |
is_cdn |
String |
否 |
“1” 或 “0”,默认为 “0” |
是否开启CDN加速,”1” 表示开启 ,”0” 表示不开启,需频繁下载的资源文件建议开启,开启后可避免产生较大的费用 |
belong_app_token |
String |
否 |
当下载其他用户的自定义 file_token 时需要指定对方的 app_token 否则只会下载自己的自定义 file_token 文件 |
|
return_json |
String |
否 |
“1” 或 “0”,默认值为 “0” |
接口返回是 json 格式还是实际文件的 302 跳转链接,该参数多用于 js 库中用来只获取文件的下载地址 |
响应参数
有三种响应参数:
如果 return_json = “1” 时,则返回 json 格式,json 内容请参阅下表;
如果 API 请求参数设置成重定向,HTTP 返回码 200,返回 body 为文件内容;
如果 API 请求参数设置成非重定向,HTTP 返回码 302,返回 header 头 Location 参数为文件下载地址;
注:如果上传文件时指定了密码,则只能通过上述第 2 条获取文件下载地址,然后通过 “下载密码保护文件” 接口获取文件内容
名称 类型 描述
file_name String 上传时的文件名称。 file_suffix String
上传时的文件后缀名。 file_url String 文件下载地址(如果是私有文件,文件下载地址使用默认的有效期 600s)
失败响应
会返回 4xx
或 5xx
,并在响应体中提供一段 JSON
格式的详细错误信息,通用的错误可以参考错误代码章节,使用下表可以查询到
获取下载地址 API 的错误码。
返回码 返回信息
20202 download file fail - 获取文件下载链接失败,状态码 500
30002 sign error - 验签失败,接口 signature 与后台计算结果不一致
30004 app token not exist - app_token 不存在
30009 query file info error - 下载文件时查询文件信息读库失败, 状态码
500
30010 download file error - 获取下载文件链接失败,状态码 500
30011 file token not exist - 下载文件时,传递的
file_token,对应的文件不存在,状态码 404
30019 incorrect signature - 签名验签失败
shell
curl "https://jfile.cloudpnr.com/file/v6/files?app_token=app-66a4740a-deef-42e5-85b0-089cf86de1ef&expires=600&file_token=54a3ba55-9967-3f71-b4cf-2610ce43caa6&signature=efa4048aee10a0f2ceab6540368a141eee6f28c28ffac9dafda218c415482f27"
python
import requests
url = "http://jua.huifutest.com/file/v6/files" # v6 测试服务器
# 拼接请求参数
file_info = {
'file_token': file_token,
'app_token': app_token,
'expires': '600'
}
# 根据参数 key 的值 顺序拼接其 key=value& , 实际做代码操作时, 可以使用排序方法拼接更为合适, 以下只做例子展示
encrypt_dict = {
'app_token': file_info['app_token'],
'file_token': file_info['file_token'],
'expires': file_info['expires']
}
keys = encrypt_dict.keys()
keys = sorted(keys, reverse=False)
# 拼接 key 和 value 值
values = ''
for key in keys:
value = str(encrypt_dict.get(key))
if len(value) == 0:
continue
values = values + '&' + str(key) + '=' + value
plain_text = 'POST' + values[1:]
# 对拼接好的字符串, 以 app_key 作为秘钥进行 hmacsha256 加密处理
file_info['signature'] = hmacsha256(plain_text, app_key)
# 获取文件的下载地址
response = requests.get(url, params=file_info)
print(response.status_code) # 打印状态码
print(response.text) # 打印返回内容
java
建议,引入 status-file,具体请参考”JAVA-SDK说明”
成功响应
200
{
"file_name": "test.txt",
"file_suffix": "txt",
"file_url": "http://jfile.cloudpnr.com/8ed14c50-a344-11e7-bf68-005056c00008.jpeg?Signature=bTbWQiXztuiDXmr1JuOw6MYfPmY%3D&OSSAccessKeyId=LTAIazOFLTVB223123mUh9&Expires=15065231266708"
}
失败响应
400
{
"message": "incorrect signature",
"return_code": 30019
}
删除文件¶
删除指定 file_token 的文件。
HTTP Request
DELETE http://jua.huifutest.com/file/v6/files
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
file_token |
String |
是 |
文件 ID |
|
password |
String |
否 |
如果上传的文件有密码,需提供密码 |
响应参数
返回 200 状态码表示删除成功。
失败响应
会返回 4xx
或 5xx
,并在响应体中提供一段 JSON
格式的详细错误信息,通用的错误可以参考错误代码章节,使用下表可以查询到
删除文件 API 的错误码。
返回码 返回信息
30002 sign error - 验签失败,接口 signature 与后台计算结果不一致
30004 app token not exist - app_token 不存在
30011 file token not exist - 删除文件时,传递的 file_token
对应的文件不存在,状态码 404
30019 incorrect signature - 签名验签失败
30020 password incorrect - 密码与上传的不匹配
30021 delete file error - 删除文件失败,无法删除远端文件
shell
curl -X DELETE \
-F "files=@/tmp/test.txt" \
-F "password=1234567890" \
-F "app_token=app-a8187ae7-5671-4888-4321-2cc8c4d476ba" \
-F "file_token=4b37df98-259e-11e7-a963-f45c898f6be5" \
-F "signature=ce879cded4867fe35d8afa7a08a40e5ac3f8fd80a93da717e9048b2c99840f80" \
http://jua.huifutest.com/file/v6/files
python
import requests
url = "http://jua.huifutest.com/file/v6/files" # 测试服务器
# 拼接请求参数
file_info = {
'file_token': file_token,
'app_token': app_token,
'password': password
}
# 根据参数 key 的值 顺序拼接其 value , 实际做代码操作时, 可以使用排序方法拼接更为合适, 以下只做例子展示
encrypt_dict = {
'app_token': file_info['app_token'],
'file_token': file_info['file_token'],
'password': file_info['password']
}
keys = encrypt_dict.keys()
keys = sorted(keys, reverse=False)
# 拼接 key 和 value 值
values = ''
for key in keys:
value = str(encrypt_dict.get(key))
if len(value) == 0:
continue
values = values + '&' + str(key) + '=' + value
plain_text = 'POST' + values[1:]
# 对拼接好的字符串, 以 app_key 作为秘钥进行 hmacsha256 加密处理
file_info['signature'] = hmacsha256(plain_text, app_key)
# 删除文件
response = requests.delete(url, data=file_info)
print(response.status_code) # 打印状态码
print(response.text) # 打印返回内容
java
建议,引入 status-file,具体请参考”JAVA-SDK说明”
成功响应
200
失败响应
404
下载密码保护文件¶
临时下载链接和连接的有效期由接口获取下载地址
生成,有效期内输入密码即可下载。
HTTP Request
GET http://jua.huifutest.com/file/v6/download
请求参数
head 中添加密码
使用浏览器时,输入临时下载地址会弹出授权对话框,在对话框中输入文件的密码即可
通过 API 调用时,将密码添加在 HTTP 请求头的 Authorization 字段,
Authorization
的计算方式:base64encode(":"+password)
例如:
GET /file/v6/download?xxxxx=xxxxxx HTTP/1.1
Host: http://jua.huifutest.com
Authorization: Basic amZfdGVzdDpqZl8yOTFYRUZWUEJG
响应参数
名称 类型 描述
(body) 二进制流 文件的内容
调用成功后,将文件二进制流返回,并修改响应体中文件的原始文件名。
失败响应
会返回 4xx
或 5xx
,并在响应体中提供一段 JSON
格式的详细错误信息,通用的错误可以参考错误代码章节,使用下表可以查询到
获取密码保护文件 API 的错误码。
返回码 返回信息
20202 download file fail - 下载文件出错,状态码 400 或 500
20207 file expired - 临时文件有效期超时,状态码 400
30001 params exception - 获取参数失败,状态码 400
30011 file token not exist - 文件ID不存在,状态码 400
共享文件¶
jarvis 用户可以将自己的某一个目录下的 file_token 共享给其他 jarvis 用户下载,被共享的 jarvis 用户只能下载到上传方指定共享目录下的文件。
获取所有共享的路径¶
HTTP Request
GET http://jua.huifutest.com/file/v6/share
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
page_number |
Int |
是 |
当前页码,默认为 “1” |
|
page_count |
Int |
否 |
分页条数,默认为 “10” |
响应参数
名称 |
类型 |
描述 |
---|---|---|
total_page |
String |
总页数 |
current_page |
String |
当前页 |
path_list |
Array |
共享路径列表 |
path_list:
名称 |
类型 |
描述 |
---|---|---|
file_path |
String |
共享文件夹路径 |
guest_count |
String |
共享给其它 app_token的个数 |
获取指定路径的共享用户列表¶
HTTP Request
GET http://jua.huifutest.com/file/v6/share/guest
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
file_path |
String |
是 |
共享文件夹路径 |
|
page_number |
Int |
是 |
当前页码,默认为 “1” |
|
page_count |
Int |
否 |
分页条数,默认为 “10” |
响应参数
名称 |
类型 |
描述 |
---|---|---|
total_page |
String |
总页数 |
current_page |
String |
当前页 |
guest_info |
Array |
共享给其它 app_token的列表 |
guest_info:
名称 |
类型 |
描述 |
---|---|---|
guest_app_token |
String |
访客的 app_token |
insert_time |
String |
加入共享的时间 |
添加共享用户¶
HTTP Request
POST http://jua.huifutest.com/file/v6/share/guest
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
file_path |
String |
是 |
共享文件夹路径 |
|
guest_app_token |
Int |
是 |
访客的 app_token |
|
app_token |
Int |
否 |
app_token |
响应参数
API 调用成功后会返回 200,其他返回码请见通用返回码
删除共享用户¶
HTTP Request
DELETE http://jua.huifutest.com/file/v6/share/guest
请求参数
名称 |
类型 |
是否必须 |
限制 |
描述 |
---|---|---|---|---|
file_path |
String |
是 |
共享文件夹路径 |
|
guest_app_token |
Int |
是 |
访客的 app_token |
|
app_token |
Int |
否 |
app_token |
响应参数
API 调用成功后会返回 200,其他返回码请见通用返回码
SDK 说明¶
SDK 介绍¶
为了方便客户端上传和下载文件,提供以下 SDK。
Python SDK¶
提供文件上传、下载和删除的 Python 原生 SDK;
Java SDK¶
提供文件上传、下载和删除的 Java SDK。
通过 pom 依赖中 添加 saturn-file 可参考:”status-file接入指南”
saturn-file
1)引入依赖
pom.xml文件加入以下依赖:
<dependency>
<groupId>com.huifu.saturn</groupId>
<artifactId>saturn-file</artifactId>
<version>1.0.6.8</version>
</dependency>
2)使用说明
请见:”status-file说明”
iOS SDK¶
提供文件上传、下载和删除的 iOS 原生 SDK;