特别好的一个文章解析:
https://blog.youkuaiyun.com/laiyaxing/article/details/51585755
一:发送请求主要有两种方法。
抽象类URLConnection是所有类的超类,他代表应用程序和URL之间的通信连接。个人感觉这两个连接方式除了在一开始的:通过在 URL 上调用 openConnection 方法创建连接对象语法上略有不同之外,其余的差不太多
1.使用HttpURLConnection发送Post和Get请求。
URL url=new URL(posturl);HttpURLConnection conn=(HttpURLConnection) url.openConnection();
2.使用URLConnection发送Post和Get请求。
URL url=new URL(posturl); URLConnection conn=url.openConnection();
二:主要流程是下面四步:
1.通过在URL上调用openconnetcion方法创建连接
2.设置请求参数,属性,请求正文(即需要提交的数据)
3.使用connect方法简历到远程对象的实际连接(可省略),为啥?
因为:connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。
无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。4.远程对象变为可用,获取response返回的相应信息
三:一个使用HttpURLConnection类实现的post请求实例
public static String sendServicePost(String url, String request, String ContentType) {
String result = "";
try {
/*一 定义相关变量*/
PrintWriter out = null;//存储请求
BufferedReader in = null;//存储接口返回的response
/*二 获取访问地址*/
//1.1得到网络访问对象java.net.HttpURLConnection
URL realUrl = new URL(url);
/*设置请求参数,以流的形式连接*/
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
//2.1.设置http的请求头
conn.setRequestProperty("accept", "*/*");
//2.2.设置请求的Contenttype
if (ContentType == null || ContentType.equals("")) {
if (isJson(request)) {
conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
} else {
if (url.toLowerCase().contains(".asmx")) {
conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
} else {
conn.setRequestProperty("Content-Type", "application/xml;charset=utf-8");
}
}
} else {
conn.setRequestProperty("Content-Type", ContentType);
}
//2.3.特殊处理:如果是1.0的请求则进一步具体设定setRequestProperty,并对xml格式做优化
if (url.toLowerCase().contains(".asmx")) {
if (url.toLowerCase().contains("datacomparews")) {
conn.setRequestProperty("SOAPAction", "http://tempuri.org/DataTableCompare");
String Xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body>";
Xml += request.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "");
Xml += "</soap:Body></soap:Envelope>";
request = Xml;
} else {
String Xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
"<soap:Body><Request xmlns=\"http://tempuri.org/\"><requestXML>" + "<![CDATA[";
Xml += request.replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>", "");
Xml += "]]></requestXML></Request></soap:Body></soap:Envelope>";
request = Xml;
conn.setRequestProperty("SOAPAction", "http://tempuri.org/Request");
}
}
//2.4.keep-alive 发出的请求建议服务器端保留连接,这样下次向同一个服务器发请求时可以走同一个连接
conn.setRequestProperty("connection", "Keep-Alive");
//2.5.设置请求的浏览器相关属性
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
//2.6.设定接受的返回流字节码为UTF-8
conn.setRequestProperty("Accept-Charset", "utf-8");
conn.setRequestProperty("Charset", "utf-8");
//2.7.设置超时时间,如果未设置超时时间,但是访问超时了就会一直卡在这里
conn.setConnectTimeout(50000 * 12);//
conn.setReadTimeout(50000 * 12);//
//2.8.设置是否向HttpURLConnection输出,默认为false,发送post请求的不啊必须设置为true
conn.setDoOutput(true);
//2.9.设置是否从httpUrlConnection读入,默认为true,不设置也可以
conn.setDoInput(true);
/* 三.处理输入请求 ,设置请求正文,即要提交的数据*/
out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "utf-8"));
out.print(request);// 写入参数到请求中
out.flush(); //flush输出流的缓冲
/*四:处理输出接口,远程对象变为可用*/
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
result = e.getMessage();
e.printStackTrace();
}
return result;
}
总结:
URLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。
无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,
对connection对象的处理设置参数和一般请求属性和写入提交数据都必须要在connect()函数执行之前完成。对outputStream的写提交数据操作,必须要在inputStream的读操作之前。这些顺序实际上是由http请求的格式决定的。http请求实际上由两部分组成,一个是http头,所有关于此次http请求的配置都在http头里面定义,一个是正文content。connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前,就必须把所有的配置准备好。
在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,
实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文。至此,http请求的东西已经全部准备就绪。在getInputStream()函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。