node.js+android(使用HttpURLConnection和HttpClient)实现文件上传

上一篇node.js 第三方模块如何安装(使用npm)及介绍  了formidable的安装,这一篇结合android写一个文件上传的例子。

先上服务端node.js 的代码,保存为upload.js

var http = require('http');
var fs = require('fs');
var formidable = require('formidable');

var firstPage = function(res){
	res.writeHead(200, {'Content-Type': 'text/html'});
	var html = fs.readFileSync(__dirname + '/public/form.html');
	res.end(html);
}

var resultPage = function(res,data,files){
    res.setHeader('Content-Type', 'text/html');
    res.write('<p>thanks ' + data.name + '</p>');
    res.write('<ul>');
	console.log(data);
	console.log(files);

    if (Array.isArray(files.images)) {
      files.images.forEach(function(image){
        var kb = image.size / 1024 | 0;
        res.write('<li>uploaded ' + image.name + ' ' + kb + 'kb</li>');
      });
    } else {
      var image = files.images;
      var kb = image.size / 1024 | 0;
      res.write('<li>uploaded ' + image.name + ' ' + kb + 'kb</li>');
    }

    res.end('</ul>');
}

var server = http.createServer(function(req, res) {
	if (req.method == 'GET'){
		return firstPage(res);
	}

	var form = new formidable.IncomingForm;
    var data = {};
    var files = {};

    form.uploadDir = __dirname +'/file';
	form.keepExtensions = true;

	function ondata(name, val, data){
		if (Array.isArray(data[name])) {//数组
			data[name].push(val);
		} else if (data[name]) {//同key
			data[name] = [data[name], val];
		} else {//第一次
			data[name] = val;
		}
	}

	form.on('field', function(name, val){
		ondata(name, val, data);
	});

	form.on('file', function(name, val){
		ondata(name, val, files);
	});
    form.on('end', function() {
		resultPage(res,data,files);	
	});

    form.parse(req);

});
server.listen(8080);

console.log('listening on http://localhost:8080');
__dirname + '/public/form.html,在js当前目录下建立public文件夹,文件夹下建立form.html文件,文件内容如下

<html>
	<body>
		<form action="/" method="post" enctype="multipart/form-data">
		  <input type="text" name="name" placeholder="Name:" />
		  <input type="file" name="images" multiple="multiple" />
		  <input type="submit" value="Upload" />
		</form>
	</body>
</html>

代码比较简单,formidable部分可以上官网https://github.com/felixge/node-formidable看API。

运行以下看看


在浏览器中打开http://localhost:8080

选择文件,输入文件name

点击upload


后台截图


文件上传成功


再看android代码,布局文件main.xml如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textViewInfo"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"/>
        
    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/textViewInfo"
        android:layout_marginLeft="40dp"
        android:layout_marginTop="20dp"
        android:text="文件路径" 
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/textViewFile"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_below="@+id/textView1"/>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textViewFile"
        android:layout_below="@+id/textViewFile"
        android:layout_marginTop="10dp"
        android:text="上传网址" 
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/textViewUrl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView3"
        android:layout_below="@+id/textView3"/>
	
	<WebView 
	    android:id="@+id/webViewResult"
        android:layout_width="fill_parent"
        android:layout_height="100dp"
        android:layout_below="@+id/textViewUrl"
        android:layout_marginTop="30dp"/>
    
    <Button
        android:id="@+id/buttonJava"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="60dp"
        android:text="Java上传" />

    <Button
        android:id="@+id/buttonApache"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/buttonJava"
        android:layout_toRightOf="@+id/buttonJava"
        android:text="Apache上传" />

</RelativeLayout>
主程序代码如下

package com.zhang.test08_11;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Random;

import org.apache.http.HttpResponse;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.TextView;

public class Test08_11Activity extends Activity {
	
	private TextView textViewInfo;
	private TextView textViewFile;
	private TextView textViewUrl;
	private WebView webViewResult;
	private Button buttonJava;
	private Button buttonApache;
	
	private static final String UPLOAD_FILE = "/sdcard/test.jpg";
	private static final String UPLOAD_URL = "http://192.168.9.194:8080/";
	private static final int BUFFER_SIZE = 1024;
	
	//rfc1867协议
	private static final String FIELD_SEP = ": ";
	private static final String CR_LF = "\r\n";
	private static final String TWO_DASHES = "--";
	private static final String BOUNDARY;
	
    /**
     * The pool of ASCII chars to be used for generating a multipart boundary.
     */
    private final static char[] MULTIPART_CHARS =
        "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    
	static {
        StringBuilder buffer = new StringBuilder();
        Random rand = new Random();
        int count = rand.nextInt(11) + 30; // a random size from 30 to 40
        for (int i = 0; i < count; i++) {
            buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
        }
        BOUNDARY =  buffer.toString();
        Log.i("info", BOUNDARY);
	}
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        textViewInfo = (TextView)findViewById(R.id.textViewInfo);
        textViewFile = (TextView)findViewById(R.id.textViewFile);
        textViewUrl = (TextView)findViewById(R.id.textViewUrl);
        webViewResult = (WebView)findViewById(R.id.webViewResult);
        buttonJava = (Button)findViewById(R.id.buttonJava);
        buttonApache = (Button)findViewById(R.id.buttonApache);
        
        textViewFile.setText(UPLOAD_FILE);
        textViewUrl.setText(UPLOAD_URL);
        
        buttonJava.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				javaUpload();
			}
		});
        
        buttonApache.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				apacheUpload();
			}
		});
    }
    
    private void javaUpload(){
    	URL url = null;
    	try {
			url = new URL(UPLOAD_URL);
		} catch (MalformedURLException e) {
		}
		
		HttpURLConnection urlConnection = null;
    	try {
    		urlConnection = (HttpURLConnection) url.openConnection();
		} catch (IOException e) {
			textViewInfo.setText(e.getMessage());
			return;
		}
		try {
			urlConnection.setRequestMethod("POST");
		} catch (ProtocolException e) {
		}
		urlConnection.setDoOutput(true);
		urlConnection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+ BOUNDARY + "; charset=UTF-8");
		
		OutputStream out = null;
		try {
			out = new BufferedOutputStream(urlConnection.getOutputStream());//请求
		} catch (IOException e) {
			urlConnection.disconnect();
			textViewInfo.setText(e.getMessage());
			return;
		}
		
		FileInputStream fStream = null;
		StringBuilder form = new StringBuilder();
		
		form.append(TWO_DASHES + BOUNDARY + CR_LF);
		form.append("Content-Disposition" + FIELD_SEP + "form-data; name=\"name\"" + CR_LF);
		form.append("Content-Type" + FIELD_SEP + "text/plain; charset=UTF-8"+ CR_LF);
		form.append("Content-Transfer-Encoding" + FIELD_SEP + "8bit"+ CR_LF);
		form.append(CR_LF);
		form.append("testImage抓哇");
		form.append(CR_LF);
		
		form.append(TWO_DASHES + BOUNDARY + CR_LF);
		form.append("Content-Disposition" + FIELD_SEP + "form-data; name=\"images\";filename=\"test抓哇.jpg\"" + CR_LF);
		form.append("Content-Type" + FIELD_SEP + "image/jpeg; charset=UTF-8"+ CR_LF);
		form.append("Content-Transfer-Encoding" + FIELD_SEP + "binary"+ CR_LF);
		form.append(CR_LF);
		
		try {
			out.write(form.toString().getBytes("UTF-8"));
			
			fStream = new FileInputStream(UPLOAD_FILE);
			byte[] buffer = new byte[BUFFER_SIZE];
			int length = -1;
			while ((length = fStream.read(buffer)) != -1) {
				out.write(buffer,0,length);
			}
			out.write(CR_LF.getBytes("UTF_8"));
			
			out.write((TWO_DASHES + BOUNDARY + TWO_DASHES + CR_LF).getBytes("UTF-8"));
			out.flush();
		} catch (IOException e) {
			try {
				out.close();
			} catch (IOException e1) {
			}
			urlConnection.disconnect();
			textViewInfo.setText(e.getMessage());
			return;
		} finally {
			try {
				if (fStream != null) {
					fStream.close();
				}
			} catch (IOException e) {
			}
		}
		getResponseJava(urlConnection);
    }
    
    private void apacheUpload(){
    	HttpPost request = new HttpPost(UPLOAD_URL);
    	
        FileBody bin = new FileBody(new File(UPLOAD_FILE),"test阿帕奇.jpg","image/jpeg",HTTP.UTF_8);
        StringBody comment = null;
		try {
			comment = new StringBody("testImage阿帕奇", Charset.forName(HTTP.UTF_8));
		} catch (UnsupportedEncodingException e) {
		}

        MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE,
        		null, Charset.forName(HTTP.UTF_8));
        entity.addPart("images", bin);
        entity.addPart("name", comment);
        
    	request.setEntity(entity);
    	
    	getResponseApache(request);
    }
    
	private void getResponseJava(HttpURLConnection urlConnection) {
		InputStream in = null;
		try {
			in = new BufferedInputStream(urlConnection.getInputStream());//响应
		} catch (IOException e) {
			urlConnection.disconnect();			
			textViewInfo.setText(e.getMessage());
			return;
		}
		
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(in,"UTF-8"));
		} catch (UnsupportedEncodingException e1) {
		}
		StringBuilder result = new StringBuilder();
		String tmp = null;
		try {
			while((tmp = reader.readLine()) != null){
				result.append(tmp);
			}
		} catch (IOException e) {
			textViewInfo.setText(e.getMessage());
			return;
		} finally {
			try {
				reader.close();
				urlConnection.disconnect();
			} catch (IOException e) {
			}
		}
		
		webViewResult.loadDataWithBaseURL(null, result.toString(), "text/html", "UTF-8", null);
	}
    
	private void getResponseApache(HttpUriRequest request) {
		HttpClient client = new DefaultHttpClient();
    	HttpResponse response = null;
    	try {
			response = client.execute(request);
		} catch (ClientProtocolException e) {
			textViewInfo.setText(e.getMessage());
		} catch (IOException e) {
			textViewInfo.setText(e.getMessage());
		}
		
		if (response == null) {
			return;
		}
		
		String result = null;
		if (response.getStatusLine().getStatusCode() == 200) {
			try {
				result = EntityUtils.toString(response.getEntity(),HTTP.UTF_8);
			} catch (ParseException e) {
				result = e.getMessage();
			} catch (IOException e) {
				result = e.getMessage();
			}
		} else {
			result = "error response" + response.getStatusLine().toString();
		}
		//Log.i("info", result); //不乱码
		//webViewResult.loadData(result, "text/html", "UTF-8"); //乱码
		webViewResult.loadDataWithBaseURL(null, result, "text/html", "UTF-8", null);//不乱码
	}
}
别忘了加权限

 <uses-permission android:name="android.permission.INTERNET"/>

先看看运行效果



点击java上传


后台输出


文件上传成功



点击Apache上传


后台输出


文件保存成功


运行一切OK。

解释代码:

	private static final String UPLOAD_FILE = "/sdcard/test.jpg";
	private static final String UPLOAD_URL = "http://192.168.9.194:8080/";

在sd卡根目录上放上test.jpg文件, node.js+android http请求响应 讲过,不要使用localhost。

代码其它部分主要是要了解http文件上传的协议 RFC1867,http://www.ietf.org/rfc/rfc1867.txt IETF官方介绍,它提供的例子不错

6. Examples

   Suppose the server supplies the following HTML:

     <FORM ACTION="http://server.dom/cgi/handle"
           ENCTYPE="multipart/form-data"
           METHOD=POST>
     What is your name? <INPUT TYPE=TEXT NAME=submitter>
     What files are you sending? <INPUT TYPE=FILE NAME=pics>
     </FORM>

   and the user types "Joe Blow" in the name field, and selects a text
   file "file1.txt" for the answer to 'What files are you sending?'

   The client might send back the following data:

        Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"; filename="file1.txt"
        Content-Type: text/plain

         ... contents of file1.txt ...
        --AaB03x--

   If the user also indicated an image file "file2.gif" for the answer
   to 'What files are you sending?', the client might client might send
   back the following data:

        Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"
        Content-type: multipart/mixed, boundary=BbC04y

        --BbC04y
        Content-disposition: attachment; filename="file1.txt"

如果看不太懂的话,可以在搜索引擎里找 rfc1867实现。




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值