HttpUrlConnection是一个HTTP协议的UrlConnection,用于通过web收发数据。数据可以是任意类型和长度。这个类主要用于收发提前不知长度的数据流。
这个类的用法遵循以下模式:
public class MainActivity extends AppCompatActivity {
URL url = null;
TextView textView;
Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
Log.d("hello","oncreate");
handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.d("hello",msg.getData().getString("name"));
textView.setText(msg.getData().getString("name"));
return true;
}
});
new Thread(new Runnable() {
HttpURLConnection connection;
@Override
public void run() {
try {
url = new URL("https://www.baidu.com/?tn=57095150_1_oem_dg");
connection = (HttpURLConnection) url.openConnection();
InputStream in = new BufferedInputStream(connection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line=bufferedReader.readLine())!=null){
stringBuilder.append(line);
}
Message message = new Message();
Bundle bundle= new Bundle();
bundle.putString("name",stringBuilder.toString());
message.setData(bundle);
handler.sendMessage(message);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
connection.disconnect();
}
}
}).start();
}
}
这段代码访问https://www.baidu.com/?tn=57095150_1_oem_dg页面,并把获得的内容放到Textview中显示。需要注意的几点:
<uses-permission android:name="android.permission.INTERNET">uses-permission>
HttpsURLConnection
实例。这个URL当然是使用“https://”开头的URL.它允许覆写
HostnameVerifier
和SSLSocketFactory接口。一个支持SSLSocketFactory的应用程序可以提供一个自定义的X509TrustManager,
用于证书链的验证,并且一个自定义的X509KeyManager用于客户端的验证。
1.3.发送内容
setFixedLengthStreamingMode(int)
设置数据长度,如果
数据长度提前可以知道的话,或者使用setChunkedStreamingMode(int)当不知道数据长度的时候。否则,
HttpUrlConnection将
会缓冲完整的请求体,缓冲完成后才会发送,这导致了内存的浪费和延迟的增加。
public Bitmap readAssetsFile(String name){
Bitmap image = null;
InputStream inputStream = null;
try {
inputStream = getResources().getAssets().open(name);
image = BitmapFactory.decodeStream(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
finally {
if(inputStream != null) try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return image;
}
file upload
";
echo "Type: ".$_FILES["myfile"]["type"]."
";
echo "Size: ".($_FILES["myfile"]["size"]/1024)." Kb
";
echo "Temp file: " . $_FILES["myfile"]["tmp_name"]."
";
if (file_exists("D:/wamp/www/"."upload/" . $_FILES["myfile"]["name"]))
{
echo $_FILES["myfile"]["name"]." already exists. ";
}
else
{
if(move_uploaded_file($_FILES["myfile"]["tmp_name"],"D:/wamp/www/"."upload/" . $_FILES["myfile"]["name"])){
echo "Stored in: " . "upload/" . $_FILES["myfile"]["name"];
}else{
echo "Store failed";
}
}
?>
这段代码中,为了方便调错,首先将上传文件的信息都打印出来。然后 判断这个文件在服务器的upload目录下存在不?存在就什么都不做,不存在就把它存储下来。这里要注意:文件的路劲要用绝对路劲,不然会报错,什么原因这里就不深究了,反正加上绝对路劲就可以了。就这样简简单单的一些代码,就实现了文件的上传与保存。这些代码主要用来测试服务器端可以正常的接受并且保存文件。有了这些验证,我们就可以安心的专注于Android端的代码了。
urlConnection.setRequestProperty("Accept-Encoding", "identity");
getHeaderFields()
或者getInputStream()方法。比如,为了检查一个响应有没有重定向到另外一个主机,可以像如下这样:
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
if (!url.getHost().equals(urlConnection.getURL().getHost())) {
// we were redirected! Kick the user out to the browser to sign on?
...
} finally {
urlConnection.disconnect();
}
}
HttpUrlConnection支持HTTP基本的认证功能。使用Authenticator支持虚拟机级别的认证处理:
Authenticator.setDefault(new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
});
}
除非使用HTTPS,否则,这不是一种安全的用户认证方式。特别是,用户名,密码,请求,响应都没有被加密却在网络间传递。-----------------------------7d71f4234700b8
Content-Disposition: form-data; name="formhash"
59329e15
-----------------------------7d71f4234700b8
Content-Disposition: form-data; name="isblog"
-----------------------------7d71f4234700b8
Content-Disposition: form-data; name="fid"
104
-----------------------------7d71f4234700b8
可以看到请求体编程了多个块,每一块可以代表一个独立的文件。这里的name和php中$_FILES_[name]保持一致,也和input标签的name属性的值保持一致。后面还可加文件名,文件长度等信息。POST /upload_file/UploadFile HTTP/1.1
Accept: text/plain, */*
Accept-Language: zh-cn
Host: 192.168.29.65:80
Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
Content-Length: 424
Connection: Keep-Alive -----------------------------7d33a816d302b6
Content-Disposition:form-data;
name="userfile1";
filename="E:\s"Content-Type:
application/octet-stream abbXXXccc
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
name="text1" foo
-----------------------------7d33a816d302b6
Content-Disposition: form-data;
name="password1" bar
-----------------------------7d33a816d302b6--
下面的代码逐条配置了上面模板中的条目,代码中注释有很详细的解释:
package com.konka.networktest;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Created by Jinwei on 2016/6/29.
*/
public class Utils {
public static void doupLoadPic(Context context, Handler handler){
//首先设置一些常量
final String end = "\r\n";
final String twoHyphens = "--";
final String boundary = "******";
URL url = null;
HttpURLConnection httpURLConnection = null;
//1.创建URL,并且获取连接
try {
url = new URL("http://192.168.0.103:8088/php/fileupload.php");
httpURLConnection = (HttpURLConnection) url.openConnection();
//2.根据这个类的使用要求,要配置一些必要的参数
httpURLConnection.setChunkedStreamingMode(128 * 1024);// 128K,这个配置可以提高性能
httpURLConnection.setDoOutput(true); //允许输出。
httpURLConnection.setDoInput(true); //允许读入,后面我们要读取服务器端返回的信息
httpURLConnection.setUseCaches(false); //不使用缓冲
//3.设置rfc1867请求头
//3.1请求行设置 POST /upload_file/UploadFile HTTP/1.1
httpURLConnection.setRequestMethod("POST"); //请求行只需设置这一个参数即可
//3.2 Accept: text/plain, */*
httpURLConnection.setRequestProperty("Accept","ext/plain, */*");
//3.3 Accept-Language: zh-cn
httpURLConnection.setRequestProperty("Accept-Language","zh-cn");
//3.3 Host: 192.168.0.105:80
//Host 接受响应的主机,默认就是发起连接的这里,所以这里不设置
//3.4 Content-Type:multipart/form-data;boundary=---------------------------7d33a816d302b6
httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
//3.5 //User-Agent: Mozilla/4.0 (compatible; OpenOffice.org)
//浏览器类型,和我们无关,不设置
//3.6 //Content-Length: 424
//数据长度,这个类不是可以收发不知长度的数据流吗?我们不知道长度的话就不设置了。
//3/7 //Connection: Keep-Alive -----------------------------7d33a816d302b6
httpURLConnection.setRequestProperty("Connection","Keep-Alive");//这里要注意,keep-Alive后面的是请求体中的内容了。所以,请求头就设置完了
//4,设置请求体
//4.1获取输出流
DataOutputStream dout = new DataOutputStream(httpURLConnection.getOutputStream());
//4.2 写分隔符,先把Keep-Alive后面的事情做完
dout.writeBytes("--"+boundary+end);
//4.3 Content-Disposition:form-data;
dout.writeBytes("Content-Disposition:form-data;");
//4.4 name="userfile1";
dout.writeBytes("name="+"\"myfile\";");
//4.5 filename="E:\s"
dout.writeBytes("filename="+"\"one.jpg\"");
//注意这里之后有两个回车换行
dout.writeBytes(end);
dout.writeBytes(end);
//4.6 application/octet-stream abbXXXccc,这里就是正文了,而正文需要读文件,以下是读文件的部分
AssetManager am = context.getAssets();
InputStream inputStream = am.open("one.jpg");
//4.7有了文件输入流后,我们把文件读出来,写到http请求体中
byte[] buffer = new byte[8192]; // 8k
int count = 0;
while ((count = inputStream.read(buffer)) != -1) {
dout.write(buffer, 0, count);
}//这样文件就写完了
//我们只有一个文件,就这样就可以了。按照格式,文件结束还要写入分隔符
dout.writeBytes(end+"--"+boundary+end);
//这样发送部分就做完了。
//另外,我们还希望接受返回的数据。
//1.打开读流
BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf-8"));
StringBuilder builder = new StringBuilder();
String result;
//2.开始读入
while((result = br.readLine())!= null){
builder.append(result);
}
//通知UI更新
Message message = new Message();
Bundle bundle= new Bundle();
bundle.putString("name",builder.toString());
message.setData(bundle);
handler.sendMessage(message);
//最后做一些清理工作
br.close();
inputStream.close();
dout.close();
httpURLConnection.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这个这个类我完整的贴出来了,这个类中的hander用于通知UI已经收到了数据了。注意,这里并没有管文件的类型,服务器端也没有检查文件的类型,注意一下,需要的时候把它们加上。 //发送第二个文件
//boundary已经写入了,现在写文件的类型,名字等信息
//4.3 Content-Disposition:form-data;
dout.writeBytes("Content-Disposition:form-data;");
//4.4 name="userfile1";
dout.writeBytes("name="+"\"myfile1\";");
//4.5 filename="E:\s"
dout.writeBytes("filename="+"\"two.jpg\"");
//注意这里之后有两个回车换行
dout.writeBytes(end);
dout.writeBytes(end);
//打开第二个文件的流
InputStream inputStream1 = am.open("two.jpg");
while ((count = inputStream1.read(buffer)) != -1) {
dout.write(buffer, 0, count);
}//这样第二个文件就写完了
inputStream1.close();
//写入分隔符
dout.writeBytes(end+"--"+boundary+end);
//第二个文件
echo "second file arrived";
echo "Upload: ".$_FILES["myfile1"]["name"]."
";
echo "Type: ".$_FILES["myfile1"]["type"]."
";
echo "Size: ".($_FILES["myfile1"]["size"]/1024)." Kb
";
echo "Temp file: " . $_FILES["myfile"]["tmp_name"]."
";
if (file_exists("D:/wamp/www/"."upload/" . $_FILES["myfile1"]["name"]))
{
echo $_FILES["myfile1"]["name"]." already exists. ";
}
else
{
if(move_uploaded_file($_FILES["myfile1"]["tmp_name"],"D:/wamp/www/"."upload/" . $_FILES["myfile1"]["name"])){
echo "Stored in: " . "upload/" . $_FILES["myfile1"]["name"];
}else{
echo "Store failed";
}
}
服务器端多了两个文件: