2012-03-07 84 views
5

我遇到了以下問題:當通過代理使用URLConnection時,內容長度始終設置爲-1URLConnection無法通過代理正確處理內容長度

首先我檢查了代理真的返回Content-Lengthlynxwget通過代理也在努力;沒有別的路可走互聯網從本地網絡):我寫

$ lynx -source -head ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip 
HTTP/1.1 200 OK 
Last-Modified: Mon, 09 Jul 2007 17:02:37 GMT 
Content-Type: application/x-zip-compressed 
Content-Length: 30745 
Connection: close 
Date: Thu, 02 Feb 2012 17:18:52 GMT 

$ wget -S -X HEAD ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip 
--2012-04-03 19:36:54-- ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip 
Resolving proxy... 10.10.0.12 
Connecting to proxy|10.10.0.12|:8080... connected. 
Proxy request sent, awaiting response... 
    HTTP/1.1 200 OK 
    Last-Modified: Mon, 09 Jul 2007 17:02:37 GMT 
    Content-Type: application/x-zip-compressed 
    Content-Length: 30745 
    Connection: close 
    Age: 0 
    Date: Tue, 03 Apr 2012 17:36:54 GMT 
Length: 30745 (30K) [application/x-zip-compressed] 
Saving to: `WO2003-104476-001.zip' 

在Java:

URL url = new URL("ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip"); 
int length = url.openConnection().getContentLength(); 
logger.debug("Got length: " + length); 

和我得到-1。我開始調試FtpURLConnection和事實證明,必要的信息是HttpURLConnection.responses場但它永遠不會正確地從那裏居住底層:

enter image description here (有在頭Content-Length: 30745)。內容長度在您開始讀取流或甚至在讀取流之後不會更新。代碼:

URL url = new URL("ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip"); 
URLConnection connection = url.openConnection(); 

logger.debug("Got length (1): " + connection.getContentLength()); 

InputStream input = connection.getInputStream(); 

byte[] buffer = new byte[4096]; 
int count = 0, len; 
while ((len = input.read(buffer)) > 0) { 
    count += len; 
} 

logger.debug("Got length (2): " + connection.getContentLength() + " but wanted " + count); 

輸出:

Got length (1): -1 
Got length (2): -1 but wanted 30745 

現在看來似乎是在JDK6中的錯誤,所以我已經打開了新的bug#7168608

  • 如果有人可以幫我寫代碼應該返回正確的內容長度直接FTP連接,FTP連接通過代理和本地file:/網址,我將不勝感激。
  • 如果給出的問題不能用JDK6解決,建議任何其他庫肯定適用於我提到的所有情況(Apache Http Client?)。
+0

爲什麼你需要的內容長度?數據的實際流是否正確?如果是這樣,你不需要內容的長度,一切工作正常。 – jtahlborn 2012-04-03 14:08:37

+0

@jtahlborn:實際的URL是正確的(它是公共FTP,所以你可以測試)。我需要了解內容長度**,而不需要讀取流到最後,顯然可以做到這一點。 – 2012-04-03 17:43:40

回答

0

一兩件事來檢查我會做的是實際讀取響應(註銷我的頭頂,所以我們期待的錯誤):

URLConnection connection= url.openConnection(); 
InputStream input= connection.getInputStream(); 
byte[] buffer= new byte[4096]; 
while(input.read(buffer) > 0) 
    ; 
logger.debug("Got length: " + getContentLength()); 

如果你所得到的大小爲好,再看看爲了使URLConnection讀取標題而不是數據以避免讀取整個響應。

+0

倒黴:這不起作用(請參閱我的更新回答)。如果您使用任何公開代理,您可以測試自己。 – 2012-03-28 20:30:16

2

請記住,代理通常會更改基礎實體的表示形式。在你的情況下,我懷疑代理可能正在改變傳輸編碼。這反過來使Content-Length即使提供也沒有意義。

你觸犯屬於HTTP 1.1規範的以下兩個部分組成:

4.4 Message Length

  1. ...
  2. ...
  3. 如果Content-Length頭字段(第14.13節)存在時,其OCTET中的十進制值表示實體長度和傳輸長度。如果這兩個長度不同(即,如果存在Transfer-Encoding頭部字段),則不應發送Content-Length頭部字段。如果收到一個消息時同時使用Transfer-Encoding頭域和Content-Length頭域,則後者必須被忽略。

14.41 Transfer-Encoding

的傳輸編碼通用頭字段指示什麼(如果有的話)類型的轉換是爲了在發送者和接收者之間安全地傳遞它被應用到消息主體。這與內容編碼的不同之處在於,傳輸編碼是消息的屬性,而不是實體的屬性。

Transfer-Encoding  = "Transfer-Encoding" ":" 1#transfer-coding 

轉移編碼在3.6節中定義。一個例子是:

Transfer-Encoding: chunked 

如果多個編碼已應用於一個實體,所述轉移 - 值編碼必須在它們被應用的順序列出。有關編碼參數的附加信息可以由本規範未定義的其他實體標題字段提供。

許多較早的HTTP/1.0應用程序不理解Transfer-Encoding標頭。

這樣的URLConnection然後忽略Content-Length頭,按照該規範,因爲它的存在毫無意義的分塊轉讓

在調試器的截圖,目前還不清楚該Transfer-Encoding是否存在頭部。請讓我們知道...

在進一步調查 - 似乎山貓不會顯示所有返回時,你發出一個lynx -head標題。它沒有顯示Transfer-Encoding標題對於此討論至關重要。

這裏的差異與公開可見的網站

Ξ▶ lynx -useragent='dummy' -source -head http://www.bbc.co.uk                             
HTTP/1.1 302 Found 
Server: Apache 
X-Cache-Action: PASS (non-cacheable) 
X-Cache-Age: 0 
Content-Type: text/html; charset=iso-8859-1 
Date: Tue, 03 Apr 2012 13:33:06 GMT 
Location: http://www.bbc.co.uk/mobile/ 
Connection: close 

Ξ▶ wget -useragent='dummy' -S -X HEAD http://www.bbc.co.uk                             
--2012-04-03 14:33:22-- http://www.bbc.co.uk/ 
Resolving www.bbc.co.uk... 212.58.244.70 
Connecting to www.bbc.co.uk|212.58.244.70|:80... connected. 
HTTP request sent, awaiting response... 
HTTP/1.1 200 OK 
Server: Apache 
Cache-Control: private, max-age=15 
Etag: "7e0f292b2e5e4c33cac1bc033779813b" 
Content-Type: text/html 
Transfer-Encoding: chunked 
Date: Tue, 03 Apr 2012 13:33:22 GMT 
Connection: keep-alive 
X-Cache-Action: MISS 
X-Cache-Age: 0 
X-LB-NoCache: true 
Vary: Cookie 

證明由於我顯然不是你的內部網絡,我不能複製你的確切情況,但請驗證您真的不通過代理時獲得Transfer-Encoding標頭。

+0

爲什麼在分塊轉移的情況下它沒有意義?如果服務器可以傳遞整個流的長度,爲什麼消費者不能使用這些信息?這是「URLConnection」的一項任務,用於收集所有塊並隱藏消費者的協議詳細信息。但是,好的,如果規格如此說...在我從'lynx'輸出的問題中,你可以看到'Transfer-Encoding'不存在,所以我不能爲你的答案投票。 – 2012-04-03 11:18:42

+0

在你的問題中的l command命令看起來很奇怪。首先'-head'不適用於http URL - 所示的命令對我來說不適用於Lynx 2.8.7rel.2。其次,如果響應是通過代理服務器發出的,那麼您會希望在響應中看到Via:標頭。 (儘管代理人並不總是尊重這一點) – sw1nn 2012-04-03 11:37:15

+0

感謝您的評論。我給出的Lynn命令對我來說工作得很好(測試版本爲v2.8.6rel.5)。 HTTP HEAD適用於任何URL,如果你通過代理**去**:你可以嘗試任何開放代理。如果「Via」不存在,這並不意味着答覆不是來自代理。如果你希望我可以把'wget'命令輸出,但它會得到相同的輸出結果。正如我所提到的,我不能以另一種方式上網:由於防火牆原因,這是不可能的。事實上,我們的代理配置爲不將'Via'返回給客戶端。 'lynx'的輸出與Java中的輸出完全相同,請以實際情況爲準。 – 2012-04-03 13:04:30

1

我認爲這是與處理代理的ftp連接有關的jdk中的一個「bug」。當代理正在使用時,FtpURLConnection委託給HttpURLConnection。 但是,在這種情況下,FtpURLConnection似乎沒有將任何頭管理委託給此HttpURLConnection。因此,您可以正確獲取流,但我不認爲您可以訪問任何「標題」值,如內容長度或內容類型。 (這是基於對1.6的openjdk源代碼的快速瀏覽,我可能錯過了一些東西)。

+0

@dma_k wrt在jdk中的錯誤 - 顯然FTP客戶端代碼已經完全徹底檢查JDK 7. http://bugs.sun.com/view_bug.do?bug_id=6893702和http://bugs.sun.com /view_bug.do?bug_id=6519647似乎相關(雖然不完全是你的問題)。你有沒有試過JDK 7? – sw1nn 2012-04-03 21:53:08

+0

2all:如果您確認問題並且可以將其報告給Sun +分享該鏈接,我會獎勵賞金(8小時後)。即使問題在JDK7中解決(我沒有檢查過),我也無法從中受益:生產AS在Java6中,並且將在未來幾年內實現。更糟的是:代碼應該符合1.5。 – 2012-04-04 15:12:34

+1

@dma_k - 爲什麼是其他人的工作來確認您的問題?我給你我認爲是正確的答案。應該很簡單,以確認它。 – jtahlborn 2012-04-04 18:11:48