使用前
这篇文档由篠原はるな撰写,图床服务部署在子扬的服务器上。(大家快投喂子扬wwww)由于子扬服务器太弱鸡导致图片直链实际上不可用,所以大家就先用篠原はるな的服务器吧。
为了使用该服务,不应该使用境外 IP,这会导致无法访问。
由于子扬的服务器性能较差,所以:
- 如果已经有合适的图床服务,建议不要使用该文档
使用这个图床可能会导致图片加载偏慢- 如果有条件,请自行部署图床,一种部署方式将在文档末尾提供
另外,白嫖是不好的。该服务只提供在寒假实训期间应急使用,请不要在图床上存储重要内容,也不要在寒假实训以外的项目中使用。
篠原はるな将在2022年3月1日删除该图床。
使用例
Postman
以上传名为xmascard.png
的图片为例:
PUT https://cloud.icooper.cc/remote.php/dav/files/pic/pic/xmascard.png
在Headers
中填入认证信息:
Key | Value |
---|---|
Authorization | Basic cGljOndpbnRlclByb2plY3Rz |
即,如图:
在body
中指定二进制文件:
发送该请求,得到:
返回码如下:
如此,我们便成功通过 Postman 发送了上传图片的请求。
还记得图片是xmascard.png
吗?
这张图片的链接便是:https://cloud.icooper.cc/apps/sharingpath/pic/pic/xmascard.png
也就是:
后端代码
本文以okhttp
为例,展示如何在后端做上传图片的接口。
确定图片格式
由于上传的文件名是由后端指定的,因此我们需要确定上传的图片的文件名。
第一步就是确定文件格式。因为文件,不论文件名是*.jpg
还是*.png
还是什么,都不一定准确。尽管无伤大雅,现代的图片浏览方式也都不全按后缀名判断文件格式,我们还是自己检测。
确定文件格式最准确的方式就是通过二进制文件头。代码如下:
public Result formatDetect(byte[] binaryData){
// 获取二进制文件格式
StringBuilder builder = new StringBuilder();
if (binaryData == null || binaryData.length <= 0) {
return Result.error(405, "文件错误");
}
String hv;
for (int i = 0; i < 4; i++) {
// 以十六进制(基数 16)无符号整数形式返回一个整数参数的字符串表示形式,并转换为大写
hv = Integer.toHexString(binaryData[i] & 0xFF).toUpperCase();
if (hv.length() < 2) {
builder.append(0);
}
builder.append(hv);
}
String header = builder.toString();
// 确定文件格式
String HTTP_Content_Type = null;
if(header.startsWith("FFD8FF"))HTTP_Content_Type = "image/jpeg";
else if(header.startsWith("89504E47"))HTTP_Content_Type = "image/png";
else if(header.startsWith("47494638"))HTTP_Content_Type = "image/gif";
else HTTP_Content_Type = "application/octet-stream";
return Result.success(HTTP_Content_Type);
}
接收byte[]
形式的二进制文件,它的HTTP_Content_Type
被Result
包装了一层,你也可以直接返回String
。
确定文件名并上传
方法声明为:public Result uploadImg(MultipartFile inputData)
即,接收MultipartFile
形式的图像文件,上传图片。
首先试图通过MultipartFile
获取它的byte[]
形式。
byte[] binaryData = null;
try {
binaryData = inputData.getBytes();
}catch (IOException e){
e.printStackTrace();
return Result.error(405, "文件出错");
}
接下来确定文件名。
String fileType = formatDetect(binaryData).getData().toString();
if (!fileType.startsWith("image"))return Result.error(405, "文件格式错误");
// 可以从形如 "image/png" 的字符串得到 ".png" 的文件后缀名
String fileSuffix = "." + fileType.substring(6);
// 任意一次上传的图片命名为 "uid + 下划线 + 时间戳 + 文件后缀名"
String fileName = uid + "_" + System.currentTimeMillis() + fileSuffix;
在本文中的例子是用户的 uid + 下划线 + 时间戳 + 后缀名形成的文件名,以保证文件名的独一无二。
第三步,使用okhttp
上传图片。
这里先new
一个Client
:
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build();
接着,准备RequestBody
用来存放图片。
RequestBody requestBody = RequestBody.create(binaryData);
最后就可以上传了。
Request request = new Request.Builder().url(serverURL + fileName)
// serverURL 是 NextCloud 的 WebDAV 地址
.addHeader("Authorization", "在这里填你的 Authorization,即一个 Basic Auth 字符串")
.put(requestBody).build();
try(Response response = okHttpClient.newCall(request).execute()){
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
return Result.error(405, "文件上传失败");
}
将fileName
拼接在有固定格式的直链上就可以了。
链接说明
上文中的例子:https://cloud.icooper.cc/apps/sharingpath/pic/pic/xmascard.png
其中https://cloud.icooper.cc/apps/sharingpath/pic/pic/
对每一张图片都不变,只需要拼接上文件名,即可访问该图片。
用 NextCloud 部署你的图床!
嗟乎!图床服务真的很难找到合适的啊!那么,如何才能拥有自己部署的图床呢?
一个简单的方案是,使用 NextCloud 官方的 All-in-One 镜像。使用 Docker 快速部署 NextCloud。
如果无误,它应该可以通过 url 正确访问。
接下来开始部署图床:
-
为 NextCloud 安装 Sharing Path。
-
开一个专门的图床账户。
-
新建一个用于存放图片的 folder。
-
配置 Sharing Path。
Copy prefix 就是 https://{Your cloud URL}/apps/sharingpath/{Account name}
,Sharing folder 如实填写就行。
填好 Basic Auth;用 Postman 测试一下。
PUT https://{Your cloud URL}/remote.php/dav/files/{Account name}/{Sharing folder}/{pic_filename}。
上传成功。直链就是 https://{Your cloud url}/apps/sharingpath/{Account name}/{Shared folder}/{pic_filename}
。
其中这个账户名为 PicSvr,用于存放图片的文件夹为 PicMain,图片名称为 Result_of_a_detailed_api_info_in_openapi.png
。
你也可以使用 Snap 的方式部署 NextCloud。Snap 版本的 NextCloud 详见 https://snapcraft.io/nextcloud。
可能发生的问题
上面的方案在子扬的服务器 didn't work。可能是 Snap 版本的问题,也可能是插件不支持 IP 形式访问(你可以看见子扬的服务器没有绑定域名),甚至可能是华为云服务器的限制。
总之,你可能遇到很多错误,上文提供的方法也许并不 work。但是你可以这样解决:
假设你建立的图床账号名为PicSvr
,你在 NextCloud 中建了一个文件夹,用来存放图片,名为UserPicture
。你可以分享这个文件夹。
随意上传一张图片,在 NextCloud 中浏览它。运用F12
,你将会发现图片的链接,通过一系列探索,你将获得自己图片的直链。
点击左下角File settings
,你将在展开页面中获取 WebDAV 地址。假设这个地址是addr_url
,那么,通过 PUT addr_url/example.jpg,即可将example.jpg
上传。