TMaize Blog

ReqProxy

最近在做一个小玩意,用的别人的api,在本地调试的还好,部署到服务器上的时候发现对api的请求都是禁止跨域,可惜的是也没有提供jsonp接口

所以自已写了一个简单的代理http(s)请求的Servlet,用这个Servlet来访问别人的服务器,同时把结果原样返回来。

为了让自己的服务器支持跨域可以设置resp.setHeader("Access-Control-Allow-Origin", "*"),或者提供对结果进行jsonp封装的选项

参数

Demo

001

002

代码

public class ReqParm {
    private String url = null;
    private Map<String, String> urlParm = null;
    private boolean post = false;
    private boolean https = false;
    private boolean respText = false;
    private String charset = "utf-8";
    private Map<String, String> reqProperty = null;
    private boolean jsonp = false;
    private String respContentType = "text/plain";
    private String callback = null;

    // getset...
}
@WebServlet("/proxy")
public class ProxyServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        exex(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        exex(req, resp);
    }

    private void exex(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Access-Control-Allow-Origin", "*");
        req.setCharacterEncoding("utf-8");
        resp.setCharacterEncoding("utf-8");
        ByteArrayOutputStream bos = null;
        OutputStream out = null;
        PrintWriter print = null;
        try {
            ReqParm o = initParm(req);
            ReqProxy reqProxy = new ReqProxy(o.getUrl());
            reqProxy.setUrlParm(o.getUrlParm());
            reqProxy.setHttps(o.isHttps());
            reqProxy.setPost(o.isPost());
            reqProxy.setReqProperty(o.getReqProperty());
            bos = reqProxy.proxy();
            if (o.isRespText()) {
                String result = bos.toString(o.getCharset());
                if (o.isJsonp()) {
                    result = o.getCallback() + "(" + result + ");";
                }
                resp.setContentType(o.getRespContentType());
                print = resp.getWriter();
                print.write(result);
                print.flush();
            } else {
                if (bos == null) {
                    throw new Exception("bos为null");
                }
                resp.setContentType("application/octet-stream");
                resp.setHeader("Content-Disposition", "attachment;filename=\"proxy\"");
                out = resp.getOutputStream();
                bos.writeTo(out);
                out.flush();
            }
        } catch (Exception e) {
            resp.setContentType("application/json");
            ResponseMessage responseMessage = new ResponseMessage();
            responseMessage.setErrno(1);
            responseMessage.setMsg(e.getMessage());
            if (print == null) {
                print = resp.getWriter();
            }
            print.write(JsonUtils.toJson(responseMessage));
            print.flush();
        } finally {
            if (bos != null) {
                bos.close();
            }
            if (out != null) {
                out.close();
            }
            if (print != null) {
                print.close();
            }
        }
    }

    private ReqParm initParm(HttpServletRequest req) throws Exception {
        try {
            ReqParm o = new ReqParm();
            if (req.getParameter("respContentType") != null) {
                o.setRespContentType(req.getParameter("respContentType"));
            }
            if (req.getParameter("url") == null) {
                throw new Exception("url为空");
            } else {
                o.setUrl(StringUtil.iso2utf(req.getParameter("url")));
            }
            if (req.getParameter("urlParm") != null) {
                String parms = StringUtil.iso2utf(req.getParameter("urlParm"));
                Map<String, String> urlParm = new HashMap<String, String>();
                String[] array = parms.split(";");
                for (int i = 0; i < array.length; i++) {
                    int index = array[i].indexOf(':');
                    urlParm.put(array[i].substring(0, index), array[i].substring(index + 1));
                }
                o.setUrlParm(urlParm);
            }
            if (req.getParameter("post") != null && req.getParameter("post").equals("true")) {
                o.setPost(true);
            }

            if (req.getParameter("https") != null && req.getParameter("https").equals("true")) {
                o.setHttps(true);
            }
            if (req.getParameter("respText") != null && req.getParameter("respText").equals("true")) {
                o.setRespText(true);
            }
            if (req.getParameter("charset") != null) {
                o.setCharset(req.getParameter("charset"));
            }
            if (req.getParameter("reqProperty") != null) {
                Map<String, String> reqProperty = new HashMap<String, String>();
                String[] array = req.getParameter("reqProperty").split(";");
                for (int i = 0; i < array.length; i++) {
                    int index = array[i].indexOf(':');
                    reqProperty.put(array[i].substring(0, index), array[i].substring(index + 1));
                }
                o.setReqProperty(reqProperty);
            }
            if (req.getParameter("jsonp") != null && req.getParameter("jsonp").equals("true")) {
                o.setJsonp(true);
                if (req.getParameter("callback") != null) {
                    o.setCallback(req.getParameter("callback"));
                    o.setRespContentType("application/x-javascript");
                } else {
                    throw new Exception("jsonp为true没有指定callback");
                }
            }
            return o;
        } catch (Exception e) {
            throw new Exception("参数初始化:" + e.getMessage());
        }
    }
}
public class ReqProxy {

    private String url = null;
    private boolean https = false;
    private Map<String, String> urlParm = null;
    private boolean post = false;
    private Map<String, String> reqProperty = null;

    @SuppressWarnings("unused")
    private ReqProxy() {
    }

    public ReqProxy(String url) {
        this.url = url;
    }

    // getset....

    private void validation() throws Exception {
        if (url == null || url.equals("")) {
            throw new Exception("url 为空");
        } else if (url.startsWith("http")) {
            throw new Exception("url不需要携带http(s)前缀");
        }
    }

    private HttpURLConnection buildConnection() throws Exception {
        String reqUrl = url;
        HttpURLConnection httpURLConnection;
        if (!post) {
            reqUrl += buildQueryString(urlParm);
        }
        if (https) {
            HttpsURLConnection conn = (HttpsURLConnection) new URL("https://" + reqUrl).openConnection();
            // 对证书不做检验
            conn.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            httpURLConnection = conn;
        } else {
            httpURLConnection = (HttpURLConnection) new URL("http://" + reqUrl).openConnection();
        }
        
        // 设置超时
        httpURLConnection.setConnectTimeout(8000);
        httpURLConnection.setReadTimeout(8000);

        // 设置请求参数
        if (reqProperty != null) {
            for (String key : reqProperty.keySet()) {
                httpURLConnection.setRequestProperty(key, reqProperty.get(key));
            }
        }
        return httpURLConnection;
    }

    private String buildQueryString(Map<String, String> map) {
        if (map != null) {
            String result = "?";
            for (String key : map.keySet()) {
                result += key + "=" + map.get(key) + "&";
            }
            if (result.equals("?")) {
                return "";
            } else {
                return result.substring(0, result.length() - 1);
            }
        } else {
            return "";
        }
    }

    private ByteArrayOutputStream save(InputStream inputStream) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            byteArrayOutputStream.write(buffer, 0, length);
        }
        return byteArrayOutputStream;
    }

    public ByteArrayOutputStream proxy() throws Exception {
        validation();
        HttpURLConnection conn = null;
        PrintWriter out = null;
        InputStream inputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            conn = buildConnection();
            if (post) {
                conn.setRequestMethod("POST");
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setUseCaches(false);
                String parm = buildQueryString(urlParm);
                if (!parm.equals("")) {
                    out = new PrintWriter(conn.getOutputStream());
                    out.print(parm);
                    out.flush();
                }
                inputStream = conn.getInputStream();
            } else {
                inputStream = conn.getInputStream();
            }
            byteArrayOutputStream = save(inputStream);
        } catch (Exception e) {
            throw new Exception(e);
        } finally {
            if (out != null) {
                out.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return byteArrayOutputStream;
    }
}