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

来源:互联网 发布:魔兽争霸3画面优化 编辑:程序博客网 时间:2024/04/28 00:05

上一篇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]) {//同keydata[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() {@Overridepublic void onClick(View v) {javaUpload();}});                buttonApache.setOnClickListener(new View.OnClickListener() {@Overridepublic 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实现。




原创粉丝点击