国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot 實現(xiàn)文件斷點下載,實戰(zhàn)來了!

這篇具有很好參考價值的文章主要介紹了Spring Boot 實現(xiàn)文件斷點下載,實戰(zhàn)來了!。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

來源:juejin.cn/post/7026372482110079012

前言

互聯(lián)網(wǎng)的連接速度慢且不穩(wěn)定,有可能由于網(wǎng)絡(luò)故障導(dǎo)致斷開連接。

在客戶端下載一個大對象時,因網(wǎng)絡(luò)斷開導(dǎo)致上傳下載失敗的概率就會變得不可忽視。

Spring Boot 實現(xiàn)文件斷點下載,實戰(zhàn)來了!

客戶端在GET對象請求時通過設(shè)置Range頭部來告訴接口服務(wù)需要從什么位置開始輸出對象的數(shù)據(jù)。

判斷是否支持斷點下載,根據(jù)文檔:14.35.1 Byte Rangeshttps://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

// 直接判斷是否有 Accept-Ranges = bytes
boolean support = urlConnection.getHeaderField("Accept-Ranges").equals("bytes");
System.out.println("Partial content retrieval support = " + (support ? "Yes" : "No));

例如:

donald@donald-pro:~$ curl -i --range 0-9 http://localhost:8080/file/chunk/download
HTTP/1.1 206
Accept-Ranges: bytes
Content-Disposition: inline;filename=pom.xml
Content-Range: bytes 0-9/13485
Content-Length: 10
Date: Mon, 01 Nov 2021 09:53:25 GMT

直接判斷頭部 HEAD,例如:

HeadObject 接口用于獲取某個文件(Object)的元信息。使用此接口不會返回文件內(nèi)容。

HEAD /ObjectName HTTP/1.1
Host: BucketName.oss-cn-hangzhou.aliyuncs.com
Date: GMT Date
Authorization: SignatureValue

需知,對應(yīng) HTTP 狀態(tài)碼:

  • 206 Partial ContentHTTP Range 請求成功
  • 416 Requested Range Not Satisfiable statusHTTP Range 請求超出界限
  • 200 OK:不支持范圍請求

小結(jié)如下:

  1. HTTP 范圍請求:需要 HTTP/1.1 及之上支持,如果雙端某一段低于此版本,則認為不支持。
  2. 通過響應(yīng)頭中的 Accept-Ranges 來確定是否支持范圍請求。
  3. 通過在請求頭中添加 Range 這個請求頭,來指定請求的內(nèi)容實體的字節(jié)范圍。
  4. 在響應(yīng)頭中,通過 Content-Range 來標(biāo)識當(dāng)前返回的內(nèi)容實體范圍,并使用 Content-Length 來標(biāo)識當(dāng)前返回的內(nèi)容實體范圍長度。
  5. 在請求過程中,可以通過 If-Range 來區(qū)分資源文件是否變動,它的值來自 ETag 或者 Last-Modifled。如果資源文件有改動,會重新走下載流程。

生產(chǎn)實戰(zhàn)

開發(fā)也得依靠依據(jù),設(shè)定好邊界,才能掌控全局。

有現(xiàn)成的文檔,來看阿里云文檔https://help.aliyun.com/document_detail/39571.html

  • Range: bytes=0-499:表示第0~499字節(jié)范圍的內(nèi)容。
  • Range: bytes=500-999:表示第500~999字節(jié)范圍的內(nèi)容。
  • Range: bytes=-500:表示最后500字節(jié)的內(nèi)容。
  • Range: bytes=500-:表示從第500字節(jié)開始到文件結(jié)束部分的內(nèi)容。
  • Range: bytes=0-:表示第一個字節(jié)到最后一個字節(jié),即完整的文件內(nèi)容。

HTTP Range 是否合法對應(yīng)處理:

  • 如果 HTTP Range 請求合法,響應(yīng)返回值為 206 并在響應(yīng)頭中包含 Content-Range
  • 如果 HTTP Range 請求不合法,或者指定范圍不在有效區(qū)間,會導(dǎo)致 Range 不生效,響應(yīng)返回值為200,并傳送整個 Object 內(nèi)容。

如下為 HTTP Range 請求不合法的示例及錯誤說明: 假設(shè) Object 資源大小為1000字節(jié),Range 有效區(qū)間為0~999

  • Range: byte=0-499:格式錯誤,byte 應(yīng)為 bytes。
  • Range: bytes=0-1000:末字節(jié) 1000 超出有效區(qū)間。
  • Range: bytes=1000-2000:指定范圍超出有效區(qū)間。
  • Range: bytes=1000-:首字節(jié)超出有效區(qū)間。
  • Range: bytes=-2000:指定范圍超出有效區(qū)間。

舉一些栗子:

# 正常范圍下載
donald@donald-pro:~$ curl -i --range 0-9 http://localhost:8080/file/chunk/download
HTTP/1.1 206
Accept-Ranges: bytes
Content-Disposition: inline;filename=Screen_Recording_20211101-162729_Settings.mp4
Content-Range: bytes 0-9
Content-Type: application/force-download;charset=UTF-8
Content-Length: 16241985
Date: Wed, 03 Nov 2021 09:50:50 GMT

服務(wù)端 - 業(yè)務(wù)開發(fā)

這里以 SpringBoot 為栗子,Spring Boot 基礎(chǔ)就不介紹了,推薦看這個實戰(zhàn)項目:

https://github.com/javastacks/spring-boot-best-practice

  1. 對外支持 range 下載
  2. 底層存儲:使用 ceph
  3. Controller 如下:
@Slf4j
@RestController
public class Controller {
    @Autowired
    private FileService fileService;

    /**
     * 下載文件
     *
     * 對外提供
     *
     * @param fileId 文件Id
     * @param token token
     * @param accountId 帳號Id
     * @param response 響應(yīng)
     */
    @GetMapping("/oceanfile/download")
    public void downloadOceanfile(@RequestParam String fileId,
                                  @RequestHeader(value = "Range") String range,
                                  HttpServletResponse response) {

        this.fileService.downloadFile(fileId, response, range);
    }
}
  1. Service 如下:
@Slf4j
@Service
public class FileService {
    @Autowired
    private CephUtils cephUtils;

    /**
     * 直接下載文件
     *
     * Tips: 支持斷點下載
     * @param fileId 文件Id
     * @param response 返回
     * @param range 范圍
     */
    public void downloadFile(String fileId, HttpServletResponse response, String range) {
        // 根據(jù) fileId 獲取文件信息
        FileInfo fileInfo = getFileInfo(fileId);

        String bucketName = fileInfo.getBucketName();
        String relativePath = fileInfo.getRelativePath();

        // 處理 range,范圍信息
        RangeDTO rangeInfo = executeRangeInfo(range, fileInfo.getFileSize());

        // rangeInfo = null,直接下載整個文件
        if (Objects.isNull(rangeInfo)) {

            cephUtils.downloadFile(response, bucketName, relativePath);
            return;
        }
        // 下載部分文件
        cephUtils.downloadFileWithRange(response, bucketName, relativePath, rangeInfo);
    }

    private RangeDTO executeRangeInfo(String range, Long fileSize) {

        if (StringUtils.isEmpty(range) || !range.contains("bytes=") || !range.contains("-")) {

            return null;
        }

        long startByte = 0;
        long endByte = fileSize - 1;

        range = range.substring(range.lastIndexOf("=") + 1).trim();
        String[] ranges = range.split("-");

        if (ranges.length <= 0 || ranges.length > 2) {

            return null;
        }

        try {
            if (ranges.length == 1) {
                if (range.startsWith("-")) {

                    //1. 如:bytes=-1024  從開始字節(jié)到第1024個字節(jié)的數(shù)據(jù)
                    endByte = Long.parseLong(ranges[0]);
                } else if (range.endsWith("-")) {

                    //2. 如:bytes=1024-  第1024個字節(jié)到最后字節(jié)的數(shù)據(jù)
                    startByte = Long.parseLong(ranges[0]);
                }
            } else {
                //3. 如:bytes=1024-2048  第1024個字節(jié)到2048個字節(jié)的數(shù)據(jù)
                startByte = Long.parseLong(ranges[0]);
                endByte = Long.parseLong(ranges[1]);
            }
        } catch (NumberFormatException e) {
            startByte = 0;
            endByte = fileSize - 1;
        }

        if (startByte >= fileSize) {

            log.error("range error, startByte >= fileSize. " +
                    "startByte: {}, fileSize: {}", startByte, fileSize);
            return null;
        }

        return new RangeDTO(startByte, endByte);
    }
}

以上內(nèi)容,大家可以收藏起來,如果以后遇到這樣的場景,分分鐘搞定!

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協(xié)程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優(yōu)雅的方式??!

5.《Java開發(fā)手冊(嵩山版)》最新發(fā)布,速速下載!

覺得不錯,別忘了隨手點贊+轉(zhuǎn)發(fā)哦!文章來源地址http://www.zghlxwxcb.cn/news/detail-604483.html

到了這里,關(guān)于Spring Boot 實現(xiàn)文件斷點下載,實戰(zhàn)來了!的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • JAVA面試題分享五百一十一:Spring Boot基于WebUploader實現(xiàn)超大文件上傳和斷點續(xù)傳

    JAVA面試題分享五百一十一:Spring Boot基于WebUploader實現(xiàn)超大文件上傳和斷點續(xù)傳

    目錄 前言 目標(biāo) 實現(xiàn)思路 大文件分片 合并分片 斷點續(xù)傳 代碼實現(xiàn) 1、webuploader組件中,分片上傳怎么開啟? 2、webuploader組件中,文件的md5值如何計算? 3、webuploader組件中,分片文件的md5值如何計算? 4、webuploader組件中,分片上傳的的請求在哪里觸發(fā)? 5、前端、后端如何校

    2024年02月19日
    瀏覽(28)
  • Spring Boot + WebSocket 實時監(jiān)控,實戰(zhàn)來了!

    Spring Boot + WebSocket 實時監(jiān)控,實戰(zhàn)來了!

    此異常非彼異常,標(biāo)題所說的異常是業(yè)務(wù)上的異常。 最近做了一個需求,消防的設(shè)備巡檢,如果巡檢發(fā)現(xiàn)異常,通過手機端提交,后臺的實時監(jiān)控頁面實時獲取到該設(shè)備的信息及位置,然后安排員工去處理。 因為需要服務(wù)端主動向客戶端發(fā)送消息,所以很容易的就想到了用

    2024年02月05日
    瀏覽(25)
  • spring boot 阿里云oss 文件分片上傳、斷點續(xù)傳

    spring boot 阿里云oss 文件分片上傳、斷點續(xù)傳

    文章目錄 前言 一、申請阿里云oss 二、上代碼 總結(jié) ? ? ? 阿里云對象存儲OSS(Object Storage Service)是一款海量、安全、低成本、高可靠的云存儲服務(wù),可提供99.9999999999%(12個9)的數(shù)據(jù)持久性,99.995%的數(shù)據(jù)可用性。多種存儲類型供選擇,全面優(yōu)化存儲成本。 ? ? 您可以使用阿

    2024年02月07日
    瀏覽(26)
  • Spring Boot + Redis 延時雙刪功能,實戰(zhàn)來了!

    Spring Boot + Redis 延時雙刪功能,實戰(zhàn)來了!

    在多線程并發(fā)情況下,假設(shè)有兩個數(shù)據(jù)庫修改請求,為保證數(shù)據(jù)庫與redis的數(shù)據(jù)一致性,修改請求的實現(xiàn)中需要修改數(shù)據(jù)庫后,級聯(lián)修改Redis中的數(shù)據(jù)。 請求一:A修改數(shù)據(jù)庫數(shù)據(jù) B修改Redis數(shù)據(jù) 請求二:C修改數(shù)據(jù)庫數(shù)據(jù) D修改Redis數(shù)據(jù) 并發(fā)情況下就會存在A — C — D — B的情況

    2024年02月08日
    瀏覽(16)
  • Spring Boot實現(xiàn)文件上傳和下載

    1.文件上傳 在pom.xml文件中添加依賴: spring-boot-starter-web 和 spring-boot-starter-thymeleaf 。 創(chuàng)建一個上傳前端的頁面,包括一個表單來選擇文件和一個提交按鈕。 在Controller中添加一個POST方法,該方法接受 MultipartFile 參數(shù),將文件保存在服務(wù)器上。 在application.properties文件中配置上

    2024年02月04日
    瀏覽(20)
  • Spring Boot 項目代碼混淆,實戰(zhàn)來了,再也不用擔(dān)心代碼泄露了!

    Spring Boot 項目代碼混淆,實戰(zhàn)來了,再也不用擔(dān)心代碼泄露了!

    簡單就是把代碼跑一哈,然后我們的代碼 .java文件 就被編譯成了 .class 文件 就是針對編譯生成的 jar/war 包 里面的 .class 文件 逆向還原回來,可以看到你的代碼寫的啥。 比較常用的反編譯工具 JD-GUI ,直接把編譯好的jar丟進去,大部分都能反編譯看到源碼: 那如果不想給別人反

    2023年04月26日
    瀏覽(18)
  • Spring Boot實現(xiàn)對超大文件進行異步壓縮下載

    Spring Boot實現(xiàn)對超大文件進行異步壓縮下載

    ?在Web應(yīng)用中,文件下載功能是一個常見的需求,特別是當(dāng)你需要提供用戶下載各種類型的文件時。本文將演示如何使用Spring Boot框架來實現(xiàn)一個簡單而強大的文件下載功能。我們將創(chuàng)建一個RESTful API,通過該API,用戶可以下載問價為ZIP壓縮文件。 首先,確保你已經(jīng)創(chuàng)建了一個

    2024年02月07日
    瀏覽(24)
  • minio + linux + docker + spring boot實現(xiàn)文件上傳與下載

    minio + linux + docker + spring boot實現(xiàn)文件上傳與下載

    檢查linux內(nèi)核,必須是3.10以上 安裝docker 啟動docker 搜索鏡像 拉取鏡像 啟動minio -p: 指定端口映射,格式為:主機端口:容器端口 (這里注意要映射兩個,否則API會訪問不到) -e “MINIO_ROOT_USER=vinci” minio用戶名; -e MINIO_SECRET_KEY=123456 minio 密碼 -d: 后臺運行容器,并返回容器ID; -

    2024年02月07日
    瀏覽(27)
  • Spring Boot整合Minio實現(xiàn)上傳憑證、分片上傳、秒傳和斷點續(xù)傳

    Spring Boot整合Minio后,前端的文件上傳有兩種方式: 文件上傳到后端,由后端保存到Minio 這種方式好處是完全由后端集中管理,可以很好的做到、身份驗證、權(quán)限控制、文件與處理等,并且可以做一些額外的業(yè)務(wù)邏輯,比如生成縮略圖、提取元數(shù)據(jù)等。 缺點也很明顯: 延遲時

    2024年02月04日
    瀏覽(24)
  • lazarus、delphi文件Http下載斷點續(xù)傳的實現(xiàn)

    下載大文件時,斷點續(xù)傳是很有必要的,特別是網(wǎng)速度慢且不穩(wěn)定的情況下,很難保證不出意外,一旦意外中斷,又要從頭下載,會很讓人抓狂。斷點續(xù)傳就能很好解決意外中斷情況,再次下載時不需要從頭下載,從上次中斷處繼續(xù)下載即可,這樣下載幾G或十幾G大小的一個

    2024年02月13日
    瀏覽(34)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包