java 使用图片代理程序,解决网站图片防盗链机制(测试百度,QQ空间有效)

4 篇文章 0 订阅

业务场景

1、页面引用其他站点图片的时候,由于某些站点存在图片的防盗链机制,所以在引用图片的时候,返回的一张默认的图片,而不是原图片。
2、使用java完成一个代理程序,代理所有的存在防盗链机制的图片请求,绕过防盗链机制,返回原图片

解决思路

1、代理请求传输的http头信息Host,使用图片url的Host,而自身站点的Host地址
2、代理请求传输的http头信息Referer,使用图片url的Host,前面加上”http://”
3、完成以上1、2的操作,用以模拟图片本身站点对图片的请求,绕过反防盗链机制

代理相关的工具类

当中使用了Apache Commons IO,解决的网络图片获取不完整的bug(需要的包请点击下载)

package lib;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import com.mysql.jdbc.StringUtils;
import dto.ImageData;

/**
 * 用于获取url的图片数据
 * @author yuyu
 *
 */
public class GetProxyImage {
     /**
     * 根据传入的url将结果以byte[]的数据返回
     * @param url 需要请求的url
     * @return
     * @throws Exception
     */
    public static ImageData getImage(String url)throws Exception{

        //当传入的url返回不为空的时候,读取数据
        ImageData back=null;
        InputStream input;
        if(!StringUtils.isNullOrEmpty(url)){
            try{
                back =new ImageData();
                String ContentType=null;
                //设置请求的头信息
                URL urlInfo = new URL(url);
                URLConnection connection = urlInfo.openConnection();
                //设置头信息
                connection.addRequestProperty("Host", urlInfo.getHost());
                connection.addRequestProperty("Connection", "keep-alive");
                //强制要求缓存服务器在返回缓存的版本之前将请求提交到源头服务器进行验证。
                connection.addRequestProperty("Cache-Control", "no-cache");
                //使用url的Host来标记来源
                connection.addRequestProperty("Referer", "http://"+urlInfo.getHost());
                //表示用户不愿意目标站点追踪用户个人信息。
                connection.addRequestProperty("DNT", "1");
                //强制要求缓存服务器在返回缓存的版本之前将请求提交到源头服务器进行验证。
                connection.addRequestProperty("Pragma", "no-cache");
                connection.addRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
                connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36");
                connection.connect();
                //获取头信息,图片的返回格式
                Map<String, List<String>> map = connection.getHeaderFields();
                List<String> type=map.get("Content-Type");
                ContentType=type.get(0);
                //获取请求回来的信息
                input = connection.getInputStream();

                //解决使用inputStream.available(),读取图片不完整问题
                //此方法在内部缓冲输入,因此不需要使用BufferedInputStream。
                byte[]data = IOUtils.toByteArray(input);  

                input.close();
                //设置返回信息
                back.setContentType(ContentType);
                back.setData(data);

            }catch(Exception e){
                throw new Exception("读取Url数据失败:"+url,e);
            }
        }
        return back;
    }
}

用以传输图片对象的简单类

package dto;

/**
 * 用于http图片数据请求
 * @author yuyu
 *
 */
public class ImageData {

    //图片返回的格式信息
    private String ContentType;
    //图片返回数据的字节数组
    private byte[] data;

    public String getContentType() {
        return ContentType;
    }
    public void setContentType(String contentType) {
        ContentType = contentType;
    }
    public byte[] getData() {
        return data;
    }
    public void setData(byte[] data) {
        this.data = data;
    }
    @Override
    public String toString() {
        return "ImageData [ContentType=" + ContentType + ", data长度="
                + data.length + "]";
    }

}

处理代理请求的Servlet

package proxyImage;

import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import dto.ImageData;
import lib.GetProxyImage;

@SuppressWarnings("serial")
public class ProxyImage extends HttpServlet {

    /**
     * 接收一个代理图片的url,返回代理得来的图片数据
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        String url=request.getParameter("url");

        //获取图片信息
        try {
            ImageData image = GetProxyImage.getImage(url);

            System.out.println(image);

            if(image!=null){
                //将获取到的图片返回
                response.setContentType(image.getContentType());
                //设置浏览器缓存
                response.setHeader("Cache-Control", "max-age=31536000");
                OutputStream out = response.getOutputStream();
                out.write(image.getData());         
                out.flush();
                out.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

展示jsp页面

页面的具体数据绑定使用了vue 框架(详情请点击查看)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>   
    <title>proxy image page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">

    <script src="https://cdn.jsdelivr.net/npm/vue"></script>

  </head>

  <body style="text-align:center">
    <div id="app" >
        <h2>{{ message }}</h2>  
        <input v-model="imageUrl" style="width: 800px;height: 30px;" Placeholder="请输入图片地址">
        <br>
        <div  style="display: inline-block;">   
            <h5>原图片</h5>
            <img :src="imageUrl" style="width: 400px;height: 300px;">
        </div>
        <div style="display: inline-block;">
            <h5>代理图片</h5>
            <img :src="proxyImageUrl" style="width: 400px;height: 300px;">
        </div>
    </div>
    <script>
        var app = new Vue({
              el: '#app',
              data: {
                message: '图片代理展示',
                imageUrl: ''
              },
              computed: {
                  proxyImageUrl: function () {
                      return  'servlet/ProxyImage?url='+encodeURIComponent(this.imageUrl)
                  }
              }
            })
    </script>
  </body>
</html>

测试

一、百度
1、从百度引用的图片地址:
http://a.hiphotos.baidu.com/image/w%3D230/sign=fa52b971b1de9c82a665fe8c5c8180d2/d53f8794a4c27d1eba11668c19d5ad6eddc43846.jpg
2、代理截图:
这里写图片描述
二、QQ空间
1、从QQ空间引用的图片地址:
http://a4.qpic.cn/psb?/f2006c66-5773-4a59-8984-2cbea031e9c0/WB*zO7jU3cQhrGgLSKf9Vd5c.YNcq67BGOWQmdO1qkk!/m/dEMBAAAAAAAA
2、代理截图:
这里写图片描述

总结

1、如果代理的图片过大,或者过于频繁其实可以将代理的结果缓存起来
2、这个代理程序只适合于其他站点的静态图片获取,要是动态的隐私图片可能会根据登入用户的cookie或者ip显示,这个时候就会代理失败

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值