最近在弄一个项目,需要用到android拍照图片上传到LAMP服务器中去,网上找了很多代码,都不能实现上传文件,原因是当时使用的租用虚拟主机空间,文章是这么说的:
写道
通过前一篇转载的博文,已经可以实现上传图片、文件等。不过当时是在本地服务器,当我将PHP代码放到租用的虚拟主机的时候,就出现问题了。我POST请求在服务器那边获取不到任何数据。也就是说 $_POST 和 &_FILES 都是空的。而测试POST到本地的服务器,又很正常。这就很奇怪了。
为了确实是什么问题,我是这么做的:
我写了一个HTML的form表单,提交到远程服务器上,没问题。
然后用Fiddler抓包软件,抓取HTML的表单请求包和Android发送的请求包,对比。看看有什么不一样。
最后发现,在请求包里有Transfer-Encoding: chunked的时候,服务器就获取不到参数。
当没有Transfer-Encoding: chunked而有Content-Length: xxx的时候就没问题然后回头看看Android的代码,将
//这句注释掉。并记录整个请求包的大小,设置一下
//httpURLConnection.setChunkedStreamingMode(128 * 1024);
httpURLConnection.setRequestProperty("Content-Length", ""+Data.length);就好了。
不知道为什么租用的虚拟主机不支持,害得我调试了好久。还有之前的RSA生成、长链接的实现,都受虚拟主机限制的影响。
Transfer-Encoding: chunked 表示使用分块传输编码这一机制,只在 HTTP1.1里才有。
可以不事先确定整个Request包的大小,而是将数据分块发送。
在Body中就是 一个十六进制的数字表示接下来的包的长度,然后包的内容
Request的结束就是当分块包的长度为0。比如:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
25
This is the data in the first chunk
1C
and this is the second one
3
con
8
sequence
0
(转发请注明转自:学PHP)
为了确实是什么问题,我是这么做的:
我写了一个HTML的form表单,提交到远程服务器上,没问题。
然后用Fiddler抓包软件,抓取HTML的表单请求包和Android发送的请求包,对比。看看有什么不一样。
最后发现,在请求包里有Transfer-Encoding: chunked的时候,服务器就获取不到参数。
当没有Transfer-Encoding: chunked而有Content-Length: xxx的时候就没问题然后回头看看Android的代码,将
//这句注释掉。并记录整个请求包的大小,设置一下
//httpURLConnection.setChunkedStreamingMode(128 * 1024);
httpURLConnection.setRequestProperty("Content-Length", ""+Data.length);就好了。
不知道为什么租用的虚拟主机不支持,害得我调试了好久。还有之前的RSA生成、长链接的实现,都受虚拟主机限制的影响。
Transfer-Encoding: chunked 表示使用分块传输编码这一机制,只在 HTTP1.1里才有。
可以不事先确定整个Request包的大小,而是将数据分块发送。
在Body中就是 一个十六进制的数字表示接下来的包的长度,然后包的内容
Request的结束就是当分块包的长度为0。比如:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
25
This is the data in the first chunk
1C
and this is the second one
3
con
8
sequence
0
(转发请注明转自:学PHP)
贴上代码:
package com.uploaddemo.control;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.http.HttpStatus;
import org.apache.http.ProtocolException;
import android.content.Context;
import android.util.Log;
public class UploadHelper {
private static final String TAG = "salesman";
private Context context = null;
private String serverUrl = null;
private String param1 = null;
private String param2 = null;
private String filePath = null;
private String fileName = null;
private static final int DEFAULT_BUFF_SIZE = 8192;
private static final int READ_TIMEOUT = 15000;
private static final int CONNECTION_TIMEOUT = 15000;
private UploadListener uploadListener = null;
public UploadHelper(Context context, String url, String param1, String param2, String filePath, String fileName) {
this.context = context;
this.serverUrl = url;
this.param1 = param1;
this.param2 = param2;
this.filePath = filePath;
this.fileName = fileName;
}
public void setUploadListener(UploadListener listener) {
this.uploadListener = listener;
}
public void uploadFile() throws MalformedURLException, ProtocolException, FileNotFoundException, IOException {
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "--------------et567z";// 各个参数的间隔符,可自定义,但不能与发送内容有重复部分
if (context == null || serverUrl == null || param1 == null || param2 == null || filePath == null || fileName == null) {
return;
}
URL url = new URL(serverUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
// 设置每次传输的流大小,可以有效防止手机因为内存不足崩溃
// 此方法用于在预先不知道内容长度时启用没有进行内部缓冲的 HTTP 请求正文的流。
// 租用的服务器空间这里必须去掉否则服务器接收不了任何参数
//httpURLConnection.setChunkedStreamingMode(128 * 1024);// 128K
//httpURLConnection.setRequestProperty("Content-Length", ""+ 1024 * 1024);
// 允许输入输出流
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
// 超时时间设置
httpURLConnection.setReadTimeout(READ_TIMEOUT);
httpURLConnection.setConnectTimeout(CONNECTION_TIMEOUT);
// 使用POST方法
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Connection", "Keep-alive");
httpURLConnection.setRequestProperty("Charset", "UTF-8");
httpURLConnection.setRequestProperty("Content-Type", "Multipart/form-data;boundary=" + boundary);
DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
// 发送jsonStr
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"param1\"" + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(param1);
dos.writeBytes(lineEnd);
// 发送acrion
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"param2\"" + lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(param2);
dos.writeBytes(lineEnd);
// 发送文件
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\"; filename=\"" + fileName + "\"" + lineEnd);
dos.writeBytes(lineEnd);
//dos.writeBytes("Content-Type: image/*\r\n\r\n");
String srcPath = filePath + fileName;
FileInputStream fis = new FileInputStream(srcPath);
byte[] buffer = new byte[DEFAULT_BUFF_SIZE]; // 8k
int counter = 0;
int count = 0;
// 读取文件
while ((count = fis.read(buffer)) != -1) {
dos.write(buffer, 0, count);
counter += count;
if (uploadListener != null) {
uploadListener.onUploadProcess(counter);
}
}
fis.close();
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);// 最后多出"--"作为结束
dos.flush();
if (httpURLConnection.getResponseCode() == HttpStatus.SC_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()), 8192);// 8k
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
}
if (uploadListener != null) {
uploadListener.onUploadFinished(sb.toString());
}
Log.e("salesman", "show.........");
} else {
Log.e(TAG, "Http request failed!");
if (uploadListener != null) {
uploadListener.onUploadFinished("Http request failed!");
}
}
if (httpURLConnection != null) {
httpURLConnection.disconnect();
}
}
}
package com.uploaddemo.control;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class UploadDemoActivity extends Activity {
private TextView txtVServerUrl = null;
private TextView txtVFilePath = null;
private Button btnUpload = null;
private ProgressBar progressBar = null;
private String filePath = Environment.getExternalStorageDirectory() + "/salesman/";
private String fileName = "test.jpg";
private String serverUrl = "http://www.bocn.com/upload.php";
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
progressBar.setProgress(msg.arg1);
} else if (msg.what == 1) {
Bundle b = msg.getData();
if (b == null) {
return;
}
String str = b.getString("msg");
Toast.makeText(UploadDemoActivity.this, str, Toast.LENGTH_LONG).show();
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtVServerUrl = (TextView) findViewById(R.id.ID_TxtV_ServerUrl);
txtVServerUrl.setText("serverUrl:" + serverUrl);
txtVFilePath = (TextView) findViewById(R.id.ID_TxtV_FilePath);
txtVFilePath.setText("filePath:" + filePath + fileName);
progressBar = (ProgressBar) findViewById(R.id.ID_PBar);
File file = new File(filePath, fileName);
progressBar.setMax((int) file.length());
btnUpload = (Button) findViewById(R.id.ID_Btn_Upload);
btnUpload.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
final UploadHelper UploadHelper = new UploadHelper(UploadDemoActivity.this, serverUrl, "heihei", "haha", filePath, fileName);
UploadHelper.setUploadListener(new UploadListener() {
@Override
public void onUploadProcess(int size) {
Message msg = new Message();
msg.what = 0;
msg.arg1 = size;
handler.sendMessage(msg);
}
@Override
public void onUploadFinished(String msg) {
Message msg1 = new Message();
msg1.what = 1;
Bundle b = new Bundle();
b.putString("msg", msg);
msg1.setData(b);
handler.sendMessage(msg1);
}
});
new Thread() {
@Override
public void run() {
try {
UploadHelper.uploadFile();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (org.apache.http.ProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
});
}
}
package com.uploaddemo.control;
public interface UploadListener {
public void onUploadProcess(int size);
public void onUploadFinished(String msg);
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/ID_TxtV_FilePath"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<TextView
android:text="TextView" android:id="@+id/ID_TxtV_ServerUrl" android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
<ProgressBar android:id="@+id/ID_PBar" android:layout_height="wrap_content" style="?android:attr/progressBarStyleHorizontal" android:layout_width="259dp"></ProgressBar>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/ID_Btn_Upload" android:text="上传"></Button>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.uploaddemo.control"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".UploadDemoActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RESTART_PACKAGES" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_LOGS" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</manifest>
<?php
echo "param1=".$_POST['param1'].chr(13).chr(10);
echo "param2=".$_POST['param2'].chr(13).chr(10);
$target_path = "./upload/";//接收文件目录
$target_path = $target_path . basename( $_FILES['uploadedfile']['name']);
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file ". basename( $_FILES['uploadedfile']['name']). " has been uploaded";
} else{
echo "There was an error uploading the file, please try again!" . $_FILES['uploadedfile']['error'];
}
?>