控制項 隨著互連網的發展,人們發布和擷取資訊的方式發生了根本的變化,越來越多的人開始把網路作為最重要的發布和擷取資訊的途徑,同時,能發布並令資訊共用的技術也越來越多。雖然這些技術為開發人員帶來了極大的便利,但是由於種種原因,其中有些技術還存在著這樣或那樣的缺陷。因此,開發人員在選擇和使用各種技術時,一定要認清這些技術的優點和局限性,取長補短,才能設計出功能完善的程式。
提出問題
筆者曾在建設企業內部資訊網工程中開發過基於Web的文檔資源共用資訊網站。該網站要求上傳的文檔能自動在首頁中根據文檔的類別按文檔標題串連到對應的欄目裡。針對這種需求,筆者利用IIS的文檔上傳控制項Posting Acceptor Components,結合資料庫和Web技術,開發出了一套自動化程度很高的文檔自動網頁發布系統和文檔自動網頁產生系統。在開發該系統的過程中,筆者發現IIS下的上傳控制項cpshost.dll在使用中存在一定的問題。例如,為完成上傳,筆者開發了兩個程式:程式一(Upload.asp)提供基於Web的資訊文檔上傳錄入介面;程式二(wd_writer.asp)把程式一錄入的資訊記錄到資料庫中。其中相關代碼如下:
程式一(upload.asp):
……
’提供文檔上傳的客戶介面
<form enctype=“multipart/form-data” action=“http://<%= Request.ServerVariables
(“SERVER_NAME”)%>/scripts/cpshost.dll?PUBLISH?wd_writer.asp” method=“post”>
<p>文檔主題: <input type=“text” name=“subject”><br>
作者:<input name=“author” type=“text”><br>
發布時間: <input name=“date1” type=“text”><br>
上傳文檔名(點擊瀏覽按鈕可進行選擇):<input type=“file” name=“filename”>
Destination URL: <input type=“hidden” name=“TargetURL”
value=“http://<%= Request.ServerVariables(“SERVER_NAME”)%>/users/wdls ”>
<input type=“submit” value=“發布確定”> </p>
</form>
……
程式二(wd_writer.asp):
<%'開啟資料庫
Set mydata = Server.CreateObject
(“ADODB.Connection”)
mydata.Open “DSN=xczh;UID=sa;PWD=;”
'從表單中取出各項內容
date1=Request.form(“date1”) '取時間
'取文檔主題
subject=Request.form(“subject”)
'取作者
author=Request.form(“subject”)
'取文檔檔案名稱
filename=Request.form(“filename”)
'取文檔在Web伺服器中存放的物理地址
TargetURL=Request.form(“filename”)
'寫資料庫
sqlstr=“insert into wdlsb values(” & sn & “,‘” & subject & “',‘” & date1 & “',‘”& filename & “',‘” & TargetURL & “',‘” & author & “')”
Mydata.Execute(sqlstr)
%>
上述程式的文法結構和邏輯結構都正確無誤,但在使用時卻出現了問題。當在程式一中表單的subject 、Author、filename 域中填寫漢字後,在程式二中用Request取出的表單域值為亂碼,即不能正確從表單中取出域值。此時,表單進行POST請求服務時的域值的封裝模式(enctype)為“multipart/form-data”,即RFC 1867。於是筆者把程式一進行POST請求服務時的封裝模式修改為“text”,但卻出現了“無法上傳文檔”的錯誤。筆者分析後發現,文檔上傳控制項cpshost.dll只能在表單的“multipart/form-data”封裝模式(既RFC 1867格式)下才能在瀏覽器與伺服器之間進行文檔上傳。
解決問題
筆者採用改變操作流程的方法,解決了上述問題。首先,由使用者填寫表單(程式三Upload.asp),並提交給程式四(wd_read.asp)進行預先處理。在程式四中利用session對象暫時儲存subject、author、date1、filename、targetUrl等表單域的輸入值。向使用者輸出一個確認頁面,由使用者再次確認表單。然後,設定表單的封裝模式為“multipart/form-data”,並進行上傳操作。最後,由cpshost.dll調用程式五(wd_writer.asp)。由程式五取出儲存於內建對象session中的域值,進行資料庫操作和操作確認。如果程式四齣現不可預測的錯誤,則文檔上傳失敗,不會調用程式五,因此保持了資料庫的完整性。相關代碼如下:
程式三(upload.asp):
<form action=“http://<%= Request.
ServerVariables(“SERVER_NAME”)>/wd_read.asp” method=“post">
<p>文檔主題: <input type=“text” name=“subject”><br>
作者:<input name=“author” type=“text”><br>
發布時間: <input name=“date1” type=“text”><br>
上傳文檔名(點擊瀏覽按鈕可進行選擇):<input type=“file” name=“filename”>
Destination URL: <input type=“hidden” name=“TargetURL” value=“http://<%= Request
.ServerVariables(“SERVER_NAME”)%>/users/<%=Request.ServerVariables(“LOGON_USER”) %>” size=“20”><br>
<input type=“submit” value=“發布確定”> </p>
</form>
程式四(wd-read.asp):
<% '取出程式三中的表單域值並儲存在session中
session(“subject”)=Request.form(“subject”)
session(“date1”)=Request.form(“date1”)
session(“author”)=Request.form(“author”)
session(“filename”)=Request.form(“filename”)
session(“TargetURL”)=Request.form(“TargetURL”)
%>
……
<form enctype=“multipart/form-data” action=
“http://<%= Request.ServerVariables
(“SERVER_NAME”) %>/scripts/cpshost.dll?PUBLISH?wd_writer.asp” method=“post”>
上傳檔案名稱(點擊瀏覽按鈕可進行選擇):<input type=“file” name=“filename” value=“<%=session(“filename”)%>”>
<input type=“hidden” name=“TargetURL”
value=“http://<%= Request.ServerVariables(“SERVER_NAME”) %>/users/wdls” >
<input type=“submit” value=“發布確定”> </p>
</form>
程式五(wd_writer.asp):
<% '開啟資料庫
Set mydata = Server.CreateObject
(“ADODB.Connection”)
mydata.Open “DSN=xczh;UID=sa;PWD=;”
’取各表單域的值
date1=session(“date1”) '取時間
subject=session(“subject”) '取文檔主題
author=session(“subject”) '取作者
filename=session(“filename”) '取文檔名
'取文檔在Web伺服器中存放的物理地址
TargetURL= session(“TargetURL”)
'寫資料庫,儲存文檔記錄
sqlstr=“insert into wdlsb values(” & sn & “,‘”& subject & “',‘” & date1 & “',‘”& filename & “',‘” & TargetURL &“',‘” & author & “')”
Mydata.Execute(sqlstr)
%>
完善程式
上述程式雖然已經能滿足設計時的要求,但還是有需要完善的地方。例如,由於在程式三中輸入的檔案名稱在程式四中會預置給表單域filename,所以,一旦用戶端重新輸入新的檔案名稱後提交確認,會使程式五中寫入資料庫的檔案名稱與實際上傳的檔案名稱不一致,造成網頁串連時出錯。為避免出