防盜鏈與springboot代理模式(圖片文件轉發)


在搭建自己的博客網站的時候,很有可能要引入一些外部圖片,畢竟多數人最開始不是在自己的平台上寫博客。  
因某種需要,搬運自己以前寫的博客到自己的網站時,在圖片這一步可能會出現問題,無法顯示。其中往往就是防盜鏈在起作用了

防盜鏈

定義

百度百科給的解釋是

此內容不在自己服務器上,而通過技術手段,繞過別人放廣告有利益的最終頁,直接在自己的有廣告有利益的頁面上向最終用戶提供此內容。 常常是一些名不見經傳的小網站來盜取一些有實力的大網站的地址(比如一些音樂、圖片、軟件的下載地址)然后放置在自己的網站中,通過這種方法盜取大網站的空間和流量。

可能有點不易懂,通俗的講,就是 出於某些原因(服務器或圖片來源等),從別的網站引入圖片到自己的網站中。這樣連服務器的存儲空間費用都省了( •̀ ω •́ )✧

原理

防盜鏈實現的原理就是:http協議中有個叫referer的表頭字段,采用URL的格式來表示從哪兒鏈接到當前的網頁或文件。換句話說,通過referer,網站可以檢測目標網頁訪問的來源網頁,如果是資源文件,則可以跟蹤到顯示它的網頁地址。有了referer跟蹤來源,就可以通過技術手段來進行處理,一旦檢測到來源不是本站即進行阻止或者返回指定的頁面。比如防盜鏈通常返回的403 forbidden。

實現

apache 服務器通常使用它的 Url Rewrite功能來實現

具體可參考 這篇文章

反防盜鏈

任何事物都有相對的兩面,既然有了防盜鏈,那么肯定也有反防盜鏈。

下載文件

將目標文件下載到自己的服務器,然后從本地讀取,這個方法應該算是比較憨厚的一種了。不過准確說這個也不算啥反防盜鏈

使用代理模式

就是下面詳細講的代理模式

文件代理模式

由於防盜鏈的關鍵在於referer頭部, 而瀏覽器獲取圖片時,它會老實的填上真是來源。比如從某個博客訪問,就填上博客地址。不過我們手動訪問圖片地址時,是不帶referer的,這時就可以訪問。因此,我們可以實現一個代理模式,來轉發圖片。
比如有防盜鏈的圖片地址 www.aa.com, 服務器地址 www.bb.com, 先讓服務器來請求(不帶referer)得到圖片,再將請求到的圖片轉發給目標網站(比如個人博客網站)。也就是博客上的圖片src直接填

www.bb.com/forward?url=www.aa.com

當然我們要在服務器上實現相應的圖片轉發功能。

下面將以springboot 為例,實現圖片轉發:


首先設置相應接口

    @RequestMapping(value = "/forward")
    public ResponseEntity<Resource> forward(@RequestParam(name = "url", required = true) String url){
        System.out.println("Start: ------------------------->");

        Resource resource = null;

        InputStream inputStream;
        try {
            inputStream = new URL(url).openStream();

            resource = new ByteArrayResource(toByteArray(inputStream));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseEntity.ok()
                .contentType(MediaType.IMAGE_PNG)
                .header(HttpHeaders.CONTENT_DISPOSITION, " filename=\"" + getFileName(url) + "\"")
                .body(resource);
    }

加上ResponseEntity是為了更好的控制Response,比如響應的頭部信息等。

其中的toByteArray()函數為

 private byte[] toByteArray(InputStream in){
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try {
            byte[] bytes = new byte[1024];
            int n;
            while ((n = in.read(bytes)) != -1){
                byteArrayOutputStream.write(bytes, 0, n);
            }
            System.out.println(byteArrayOutputStream.size());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return byteArrayOutputStream.toByteArray();
    }

getFileName()函數為

    private String getFileName(String url){
        String[] strs = url.split("/");
        for (String str: strs){
            // 這里我僅處理png格式的,根據需求修改即可
            if (str.toLowerCase().endsWith(".png")){
                return str;
            }
        }
        return null;
    }

最后

就以cnblog上一圖片 https://img2018.cnblogs.com/blog/1470456/201812/1470456-20181206174653015-309070173.png 舉個例子
如圖,轉發成功(~ ̄▽ ̄)~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM