1. 程式人生 > >將檔案通過http的post方法上傳到伺服器

將檔案通過http的post方法上傳到伺服器

 這實際上是模仿瀏覽器的post行為,問題的提出是本人在做一個企業內部網路的專案的時候,該企業網路與Internet是通過一臺HP-UNIX的伺服器連線的,專案需要經常從網際網路傳送一些文字檔案到內部網路的一臺Web伺服器,我們只能夠通過那臺HP-UNIX的主機進去,當時內網的Web伺服器用的是DotNet框架,很容易的寫好了檔案上傳的Web介面。這就麻煩了,我不能夠用瀏覽器直接訪問該檔案上傳頁面,所以就只好用Java寫了個模仿瀏覽器上傳檔案的程式。
環境:
內網Web伺服器:Windows2000+DotNet Framework1.0
外網主機:HP-UNIX(具體什麼版本號忘記了)、jdk1.4
 首先、我們解決容易的問題,我們知道asp.net的檔案上傳功能封裝得非常完美。很輕鬆我們就寫好了如下上傳頁面(命名為TestFileManager.aspx):

<%@ Page Language="c#" CodePage="936" %>
<%@ import Namespace="System" %>
<%@ import Namespace="System.IO" %>

<script runat="server">
 void Page_Load(Object sender, EventArgs e) {
 }
 void Button1_Click(Object sender, EventArgs e) {
  //判斷選取對話方塊選取的檔案長度是否為0
  Label1.Text="Clicked";
  //因為我的專案中用的只是xml檔案,所以有此判斷
  if (uploadfile1.PostedFile.ContentLength != 0 && uploadfile1.PostedFile.FileName.ToLower().EndsWith(".xml")) {
   try{
    string strFileName = uploadfile1.PostedFile.FileName;
    string[] strTemp = strFileName.Split(new char[]{'//'});
    strFileName = "C://"+strTemp[strTemp.Length-1];
    uploadfile1.PostedFile.SaveAs(strFileName);
    Label1.Text="測試檔案" + strFileName + "上傳成功! ";
            }
            catch (Exception exp)
            {
    Label1.Text = exp.StackTrace;
            }
  }
 }
</script>
<html>
<head>
 <title>邏輯層測試管理</title>
</head>
<body>
    <form method="post" enctype="multipart/form-data" runat="server">
        <p>
            <input id="uploadfile1" type="file" size="49" runat="server" />
            <asp:Button id="Button1" onclick="Button1_Click" runat="server" Text="上傳"></asp:Button>
        </p>
        <p>
            <asp:Label id="Label1" runat="server" Width="459px"></asp:Label>
        </p>
        <!-- Insert content here -->
    </form>
</body>
</html>


這個上傳頁面應該沒什麼好說的了,我們看看它將產生的html頁面內容:
<html>
<head>
    <title>邏輯層測試管理</title>
</head>
<body>
    <form name="_ctl0" method="post" action="TestFileManager.aspx" id="_ctl0" enctype="multipart/form-data">
<input type="hidden" name="__VIEWSTATE" value="dDwyNTIzNjA5NDU7Oz7rsE3eBYzQHDVtl+aTn96MvQW6PQ==" />

        <p>
            <input name="uploadfile1" id="uploadfile1" type="file" size="49" />
            <input type="submit" name="Button1" value="?" id="Button1" />
        </p>
        <p>
            <span id="Label1" style="width:459px;"></span>
        </p>
        <!-- Insert content here -->
    </form>
</body>
</html>

上面有一段<input type="hidden" name="__VIEWSTATE" value="dDwyNTIzNjA5NDU7Oz7rsE3eBYzQHDVtl+aTn96MvQW6PQ==" />這是它產生的相當於Session的一個值,這個值將對我們的上傳程式產生比較大的影響。
接著我們來寫Java上傳的程式,這裡要說明一點,我沒有用j2se的網路包,並不是現有的網路包不行,因為當時我正好在玩sun的BRAZIL PROJECT(http://www.sun.com/2000-0822/brazil/),感覺挺精巧的,所以就用上了brazil的網路功能。

import java.io.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.parsers.*;
import sunlabs.brazil.util.*;
import sunlabs.brazil.util.http.*;
/**
 * 該類實現上傳xml測試檔案到邏輯層
 *
 */
public class TestFileManager {
 /**
  * 提取XML一個節點的屬性值
  * @node XML節點物件
  * @strName 屬性名稱
  * @return 節點的屬性值
  */
 private static String getNodeAttributeValue(Node node, String strName) {
  NamedNodeMap nmap = node.getAttributes();
  Node tmpnode = nmap.getNamedItem(strName);
  String rtStr = "";
  if ( tmpnode != null ) {
   rtStr = tmpnode.getNodeValue().trim();
  }
  return rtStr;
 }

 public static void main(String[] args){
  if ( args.length < 1 ) {
   System.out.println("Usage: java TestFileManager xmlfilelist");
   System.exit(0);
  }
  try {
   HttpRequest request = new HttpRequest("http://192.9.200.108:80/OnlineService/TestFileManager.aspx");
   request.setMethod("GET");
   request.setRequestHeader("Cache-Control", "no-cache");
   request.setRequestHeader("Connection", "Keep-Alive");
   request.setRequestHeader("Accept", "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
   request.setRequestHeader("Accept-Encoding", "gzip, deflate");
   request.setRequestHeader("Accept-Language", "en-au");
   request.setRequestHeader("Referer", "http://rookie/OnlineService/TestFileManager.aspx");
   request.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3215; .NET CLR 1.0.3705)");
   
   request.connect();
   String strCookie = request.getResponseHeader("Set-Cookie");
   strCookie = strCookie.substring(0,strCookie.indexOf(";"));
   
   DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
   DocumentBuilder parser =dbfactory.newDocumentBuilder();
   String strTemp = request.getContent();
   

   Document xmldoc = parser.parse(new InputSource(new StringReader(strTemp)));
   NodeList nlist = xmldoc.getElementsByTagName("input");
   Node node;
   String strName = "";
   String strValue = "";
   for ( int i = 0; i < nlist.getLength(); i++) {
    node = nlist.item(i);
    strName = getNodeAttributeValue(node,"name");
    if ( strName.equals("__VIEWSTATE") ) {
     strValue = getNodeAttributeValue(node,"value");
     break;
    }
   }
   request.close();
   request = null;

   String strBoundary = null;
   String strFileName = null;
   BufferedInputStream bis = null;
   byte[] data = null;
   for ( int i=0; i<args.length;i++ ) {
    try {
     strBoundary = new String(""+(Math.random()+Math.random())).substring(2);
     strFileName = args[i];
     bis = new BufferedInputStream(new FileInputStream(strFileName));
     data = new byte[bis.available()];
     bis.read(data, 0, data.length);
     bis.close();
     System.out.println("上傳檔案 " + strFileName + "...");

     request = new HttpRequest("http://192.9.200.108:80/OnlineService/TestFileManager.aspx");
     request.setMethod("POST");
     request.setRequestHeader("Cache-Control", "no-cache");
     request.setRequestHeader("Connection", "Keep-Alive");
     request.setRequestHeader("Content-Type", "multipart/form-data; boundary=---------------------------"+strBoundary);
     request.setRequestHeader("Accept", "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
     request.setRequestHeader("Accept-Encoding", "gzip, deflate");
     request.setRequestHeader("Accept-Language", "en-au");
     request.setRequestHeader("Cookie", strCookie);
     request.setRequestHeader("Host", "rookie");
     request.setRequestHeader("Referer", "http://rookie/OnlineService/TestFileManager.aspx");
     request.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3215; .NET CLR 1.0.3705)");
     DataOutputStream dos = new DataOutputStream(request.getOutputStream());
     dos.writeBytes("-----------------------------"+strBoundary);
     dos.writeBytes("/r/nContent-Disposition: form-data; name=/"__VIEWSTATE/"");
     dos.writeBytes("/r/n/r/n"+strValue);
     dos.writeBytes("/r/n-----------------------------"+strBoundary);
     dos.writeBytes("/r/nContent-Disposition: form-data; name=/"uploadfile1/"; filename=/"" + strFileName + "/"");
     dos.writeBytes("/r/nContent-Type: text/xml");
     dos.writeBytes("/r/n/r/n");
     dos.writeBytes(new String(data));
          dos.writeBytes("/r/n-----------------------------"+strBoundary);
     dos.writeBytes("/r/nContent-Disposition: form-data; name=/"Button1/"");
     dos.writeBytes("/r/n上傳");
     dos.writeBytes("/r/n-----------------------------"+strBoundary+"--");
     dos.writeBytes("/r/n");
     dos.close();
     request.connect();

     request.close();
     request = null;
     System.out.println("檔案 " + strFileName + " 上傳成功.");
    } catch (FileNotFoundException e) {
     System.out.println("檔案 " + strFileName + " 未找到.");
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}

下面我詳細講解main方法中的具體過程
首先建立一個到伺服器http的請求
HttpRequest request = new HttpRequest("http://192.9.200.108:80/OnlineService/TestFileManager.aspx");
第一次使用的是GET方式
request.setMethod("GET");
緊接著進行一些請求的屬性設定
request.setRequestHeader("Cache-Control", "no-cache");
這裡保持連線,因為後面還要傳送資料到伺服器呢
request.setRequestHeader("Connection", "Keep-Alive");
下面是一些無關緊要的屬性設定了。
request.setRequestHeader("Accept", "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
request.setRequestHeader("Accept-Encoding", "gzip, deflate");
request.setRequestHeader("Accept-Language", "en-au");
request.setRequestHeader("Referer", "http://rookie/OnlineService/TestFileManager.aspx");
request.setRequestHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.0.3215; .NET CLR 1.0.3705)");

構造好了連線請求,然後連線
request.connect();

緊接著提取Cookie值,在後文的post中可以用到。
String strCookie = request.getResponseHeader("Set-Cookie");
strCookie = strCookie.substring(0,strCookie.indexOf(";"));

下面通過迴圈查詢,提取__VIEWSTATE的值,這個值是不能捏造的,每個新的get取得的是不一樣的。
for ( int i = 0; i < nlist.getLength(); i++) {
 node = nlist.item(i);
 strName = getNodeAttributeValue(node,"name");
 if ( strName.equals("__VIEWSTATE") ) {
  strValue = getNodeAttributeValue(node,"value");
  break;
 }
}

往伺服器組織傳送資料
DataOutputStream dos = new DataOutputStream(request.getOutputStream());
dos.writeBytes("-----------------------------"+strBoundary);//這是每個要被髮送資料間的間隔
dos.writeBytes("/r/nContent-Disposition: form-data; name=/"__VIEWSTATE/"");
dos.writeBytes("/r/n/r/n"+strValue);
dos.writeBytes("/r/n-----------------------------"+strBoundary);
這裡面是傳送檔案的部分
dos.writeBytes("/r/nContent-Disposition: form-data; name=/"uploadfile1/"; filename=/"" + strFileName + "/"");
dos.writeBytes("/r/nContent-Type: text/xml");
dos.writeBytes("/r/n/r/n");
dos.writeBytes(new String(data));
dos.writeBytes("/r/n-----------------------------"+strBoundary);
dos.writeBytes("/r/nContent-Disposition: form-data; name=/"Button1/"");
dos.writeBytes("/r/n上傳");
dos.writeBytes("/r/n-----------------------------"+strBoundary+"--");
dos.writeBytes("/r/n");
dos.close();
最後傳送,也就是執行連線的操作。最後把上面程式部署到HP-UNIX上面,就可以上傳檔案到我的邏輯層了。以上的過程用j2se的net包也可以實現的,改一改類和方法就是了。
本文敘述的是文字檔案的上傳方式,對於二進位制的檔案則需要對檔案資料進行編碼,一般使用base64的編碼。基本步驟是相同的,只要在組織檔案資料的時候對檔案內容編碼並指明編碼方式就可以了。
文中不詳處,請email:[email protected]