前面有篇博文介绍了java的URL类跨域请求,但是介绍的不是很完整,所以决定重新写篇博文详细介绍一下java的URL类。附实际案例之前首先说一些关于http协议的内容。
1. GET请求与POST请求
GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连。GET请求发送的参数如果数据是英文字母或数字,则按原样发送,如果是空格,则转换为+,如果是中文或其他字符,则直接把字符串用BASE64加密,得出如 %E4%BD%A0%E5%A5%BD 这类似的字符串,其中%XX中的XX为该符号以16进制表示的ASCII。POST请求的参数不是放在URL字符串里面,而是放在HTTP请求的正文内,请求的参数被封装起来以流的形式发送给服务端。对于GET方式提交数据的大小,HTTP协议并没有硬性限制,但某些浏览器及服务器会对它进行限制,如IE对URL长度的限制是2083字节(2K+35)。理论上POST也没有限制,可传较大量的数据。POST的安全性要比GET的安全性高。比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为登录页面有可能被浏览器缓存,如果其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery(CSRF,跨站请求伪造)攻击。一般来说,Get是向服务器索取数据的一种请求,而Post是向服务器提交数据的一种请求。
2. HTTP常见Content-Type
(1) application/x-www-form-urlencoded
浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded方式提交数据。传递的key/value会经过URL转码,所以如果传递的参数存在中文或者特殊字符需要注意。在servlet实现中,application/x-www-form-urlencoded会被特殊处理,请求参数将被放置于request.paramter,这是一个map。
(2) application/json
当我们使用content-type=application/json且后台使用@RequestBody,则无法再从request.paramter中获取请求数据。告诉服务端消息主体是序列化后的JSON 字符串。由于 JSON 规范的流行,除了低版本 IE 之外的各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理 JSON 的函数,使用 JSON 不会遇上什么麻烦。
3. HttpURLConnection简介
在JDK的java.net包中已经提供了访问HTTP协议的基本功能的类:HttpURLConnection。HttpURLConnection是Java的标准类,它继承自URLConnection,可
用于向指定网站发送GET请求、POST请求。它在URLConnection的基础上提供了如下便捷的方法:
int getResponseCode(); // 获取服务器的响应代码。
String getResponseMessage(); // 获取服务器的响应消息。
String getResponseMethod(); // 获取发送请求的方法。
void setRequestMethod(String method); // 设置发送请求的方法。
工程案例分析,本文以POST请求为主分析。
// 日志打印,不用考虑这句代码
private static final Logger LOG = LoggerFactory.getLogger(XX.class);
// HttpURLConnection的封装函数
public static Map<String, Object> sendPost(String url, String jsonData) {
BufferedReader br = null;
Map<String, Object> result = new HashMap<String, Object>();
OutputStreamWriter osw = null;
try {
// 通过给定的URL字符串创建URL
URL realUrl = new URL(url);
// 打开和URL之间的连接, ,并运行客户端访问资源。
// URLConnection conn = realUrl.openConnection();
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Accept-Charset", "utf-8");
// 下面需要根据实际情况选择Content-Type
// 1、前台为表单数据提交
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
// 2、后台接受数据的格式是requestBody
// conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false); //不允许缓存
conn.setRequestMethod("POST"); //设置POST方式连接
// Post 请求不能使用缓存
conn.setUseCaches(false);
// 获取URLConnection对象对应的输出流
osw = new OutputStreamWriter(conn.getOutputStream(), "utf-8");
// 发送请求参数
osw.write(jsonData);
// flush输出流的缓冲
osw.flush();
// 定义BufferedReader输入流来读取URL的响应
br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
String resultStr = "";
while ((line = br.readLine()) != null) {
resultStr += line;
}
result = JSON.parseObject(resultStr);
LOG.info("调用接口返回的数据:" + result);
} catch (Exception e) {
LOG.info("发送 POST,请求出现异常!" + e);
result.put("success", false);
result.put("msg", "请关闭窗口稍后请求!");
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (osw != null) {
osw.close();
}
if (br != null) {
br.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
return result;
}
// 调用sendPost接口的方法
@RequestMapping(value = "/cors")
public void Cors(HttpServletRequest request, HttpServletResponse response) {
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
response.setContentType("text/json;charset=utf-8");
// 处理调用sendPost接口的参数
String url = request.getParameter("corsUrl")==null?"":request.getParameter("corsUrl").toString();
Map<String, String> praMap = ViewUtil.convertParameterMAP(request.getParameterMap());
Map<String, Object> jsonObject = new HashMap<String, Object>();
try {
// 前台为表单数据提交或者"Content-Type = application/x-www-form-urlencoded;charset=utf-8"时,参数处理方式。
StringBuffer dataBuffer = new StringBuffer();
Set set = praMap.entrySet();
Iterator iterator = set.iterator();
while (iterator.hasNext())
{
Map.Entry mapentry = (Map.Entry) iterator.next();
String key = mapentry.getKey()==null?"" : mapentry.getKey().toString();
String value = mapentry.getValue()==null?"" : mapentry.getValue().toString();
dataBuffer.append("&");
dataBuffer.append(key);
dataBuffer.append("=");
dataBuffer.append(value);
}
String jsonData = dataBuffer.toString().substring(1);
PrintWriter out = response.getWriter();
// 后台接受数据的格式是requestBody提交或者"Content-Type = application/json;charset=utf-8"时,参数处理方式。
// jsonData = praMap.toString(); 等其他Map转成json字符串的方式。
jsonObject = sendPost(url, jsonData);
out.write(jsonObject.toString());
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
}