软件园学生在线

  • {{ item.name }}
  • 2023试用期

登录与注册

寒假实训图床方案 第二版

  • 朱哲甬
  • 2023-01-12
  • 0

使用前

这篇文档由篠原はるな撰写,图床服务部署在子扬的服务器上。(大家快投喂子扬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

即,如图:

Try_to_upload_an_image_to_nextcloud_via_postman_and_webdav

在body中指定二进制文件:

Specify_the_image_file_in_postman_and_upload_it_to_nextcloud

发送该请求,得到:

Result_after_successfully_uploading_a_picture

返回码如下:

Return_code_after_successfully_uploading_a_picture

如此,我们便成功通过 Postman 发送了上传图片的请求。


还记得图片是xmascard.png吗?

这张图片的链接便是:https://cloud.icooper.cc/apps/sharingpath/pic/pic/xmascard.png

也就是:

xmascard

后端代码

本文以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 正确访问。

接下来开始部署图床:

  1. 为 NextCloud 安装 Sharing Path。

  2. 开一个专门的图床账户。

  3. 新建一个用于存放图片的 folder。

  4. 配置 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}。

例如:https://cloud.icooper.cc/apps/sharingpath/PicSvr/PicMain/Result_of_a_detailed_api_info_in_openapi.png

其中这个账户名为 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。你可以分享这个文件夹。

Main_page_of_a_picture_service_account_in_nextcloud

随意上传一张图片,在 NextCloud 中浏览它。运用F12,你将会发现图片的链接,通过一系列探索,你将获得自己图片的直链。

点击左下角File settings,你将在展开页面中获取 WebDAV 地址。假设这个地址是addr_url,那么,通过 PUT addr_url/example.jpg,即可将example.jpg上传。

朱哲甬
朱哲甬
© 2025 软件园学生在线
Theme by Wing