最近在做一个小玩意,用的别人的api,在本地调试的还好,部署到服务器上的时候发现对api的请求都是禁止跨域,可惜的是也没有提供jsonp接口
所以自已写了一个简单的代理http(s)请求的Servlet,用这个Servlet来访问别人的服务器,同时把结果原样返回来。
为了让自己的服务器支持跨域可以设置resp.setHeader("Access-Control-Allow-Origin", "*")
,或者提供对结果进行jsonp封装的选项
参数
-
url
要代理的url,不携带http(s)和?后面的内容
-
urlParm
原url?后面的参数,需要进行一处理
?keywords=尽头&page=1 => keywords:尽头;page:1
-
reqProperty
用于setRequestProperty,不常用,构造同urlParm
-
post
是否是post请求,默认false
-
https
是否是https请求,默认false
-
respText
是否返回文本,默认false,直接返回文件流
-
respContentType
当respText为true时候,返回的类型,默认为text/plain,出现异常是application/json,jsonp为true时候是application/x-javascript,特殊情况自定义,一般上面的就很标准了
-
charset
当respText为true时候可以设置返回文本的编码,默认是utf-8
-
jsonp
是否返回jsonp,默认是false
-
callback
jsonp的回调名,
callback+"{"+result+"}";
Demo
代码
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;
}
}