2012-06-20 31 views
15

Tôi đang tải tệp JSON bằng XMLHttpRequest trong Google Chrome, Safari và Firefox. Trong cả ba trình duyệt, tôi nhận được ProgressEvent s hiển thị chính xác thuộc tính .loaded. Tuy nhiên, thuộc tính .lengthComputable là sai và thuộc tính .total bằng không. Tôi đã kiểm tra rằng tiêu đề HTTP Content-Length đang được gửi và chính xác - đó là. Phản hồi đang được mã hóa gzip, nhưng Content-length hiển thị chính xác độ dài được mã hóa (trước khi giải nén).Tại sao ProgressEvent.lengthComputable false?

Tại sao tổng chiều dài không có sẵn trong số ProgressEvent s của tôi?

Dưới đây là các tiêu đề:

HTTP/1.1 200 OK 
ETag: "hKXdZA" 
Date: Wed, 20 Jun 2012 20:17:17 GMT 
Expires: Wed, 20 Jun 2012 20:17:17 GMT 
Cache-Control: private, max-age=3600 
X-AppEngine-Estimated-CPM-US-Dollars: $0.000108 
X-AppEngine-Resource-Usage: ms=2 cpu_ms=0 api_cpu_ms=0 
Content-Type: application/json 
Content-Encoding: gzip 
Server: Google Frontend 
Content-Length: 621606 

Lưu ý: các tập tin đang được phục vụ qua Google App Engine.

Đây là JavaScript:

var req; 
if (window.XMLHttpRequest){ 
    req = new XMLHttpRequest(); 
    if(req.overrideMimeType){ 
     req.overrideMimeType("text/json"); 
    } 
}else{ 
    req = new ActiveXObject('Microsoft.XMLHTTP'); 
} 

// Listen for progress events 
req.addEventListener("progress", function (event) { 
    console.log(event, event.lengthComputable, event.total); 
    if (event.lengthComputable) { 
     self.progress = event.loaded/event.total; 
    } else if (this.explicitTotal) { 
     self.progress = Math.min(1, event.loaded/self.explicitTotal); 
    } else { 
     self.progress = 0; 
    } 
    self.dispatchEvent(Breel.Asset.ON_PROGRESS); 
}, false); 

req.open('GET', this.url); 

Lưu ý: Các console.log trong mã đó là hiển thị hàng trăm sự kiện với cập nhật .loaded s nhưng .lengthComputable luôn là sai và .total luôn là zero. self đề cập đến đối tượng chịu trách nhiệm cho điều này XMLHttpRequest.

+1

Chúng tôi có thể xem mã javascript mà bạn có đang xem dữ liệu này không? – tkone

+0

Tôi đã thêm điều đó ngay bây giờ. –

+1

bạn đã thử sử dụng tính năng này trên máy chủ công cụ ứng dụng không phải của google chưa? Nếu 'lengthComputable' là sai hơn đối tượng xhr không biết tệp đó dài bao lâu. Chúng tôi sử dụng GAE ở đây và có vấn đề lớn với hầu hết các chức năng của nó - điều này sẽ không đáng ngạc nhiên. – tkone

Trả lời

14

Nếu chiều dàiTiêu chí là sai trong XMLHttpRequestProgressEvent, điều đó có nghĩa là máy chủ không bao giờ gửi tiêu đề Content-Length trong phản hồi.

Nếu bạn đang sử dụng nginx làm máy chủ proxy, điều này có thể là thủ phạm, đặc biệt nếu nó không chuyển tiêu đề nội dung dài từ máy chủ ngược lên qua máy chủ proxy tới trình duyệt.

+0

Nếu bạn đang đặt tiêu đề có độ dài nội dung bị bỏ qua, bạn cũng phải đặt kích thước bộ đệm phản hồi của bạn để có thể giữ các byte bạn đang gửi. Nếu không trong HTTP 1.1 nó sẽ trở lại để chunking phản ứng. –

+0

Hoặc, nhiều năm sau, khi sử dụng nội dung gzip'd trong Chrome, ngay cả khi đã đặt tiêu đề phải. :-( – Arjan

1

sử dụng req.upload.addEventListener để tải lên

req.addEventListener event.lengthComputable sẽ luôn luôn là sai

req.upload.addEventListener("progress", function (event) { 
    console.log(event, event.lengthComputable, event.total); 
    if (event.lengthComputable) { 
     self.progress = event.loaded/event.total; 
    } else if (this.explicitTotal) { 
     self.progress = Math.min(1, event.loaded/self.explicitTotal); 
    } else { 
     self.progress = 0; 
    } 
    self.dispatchEvent(Breel.Asset.ON_PROGRESS); 
}, false); 
+0

Tôi đã thấy 'req.addEventListener'' event.lengthComputable' cũng đúng, có vẻ sai cho các yêu cầu lớn: cái tôi đã thử là JPG 10MB. Tôi chưa thực hiện thử nghiệm rộng rãi, nhưng bạn có thể đúng là 'lengthqputable'' 'của' req.upload' đúng hơn thường là – trysis

+1

... nhưng giống như tên cho thấy: đó là các nội dung tải lên từ trình duyệt đến máy chủ chứ không phải tải xuống từ máy chủ đến trình duyệt. – Arjan

1

Trong khi đó năm 2017, mọi thứ đều ổn trong Firefox, nhưng Chrome không hiển thị tiến trình cho nội dung gzip'd.

Điều này có vẻ là do các đặc điểm kỹ thuật khi không rõ ràng nếu loadedtotal tham chiếu đến nội dung được nén hoặc không nén. Since ngày 26 tháng 6 năm 2014 the XMLHttpRequest specifications làm rõ rằng họ nên tham khảo nội dung được truyền (nén):

6.1. Bắn các sự kiện bằng cách sử dụng giao diện ProgressEvent

[...] cho truyềndài [...] bắn một sự kiện [...] ProgressEvent, với loaded thuộc tính khởi tạo truyền, và nếu chiều dài không phải là 0, với thuộc tính lengthComputable được khởi tạo thành đúng và thuộc tính total được khởi tạo thành chiều dài.

Tuy nhiên, Chromium báo cáo 2015 lỗi "XHR's progress events should handle gzipped content" giải thích rằng mọi thứ đều khác nhau, và khẳng định:

khi mã hóa, total ở lại là 0 và lengthComputable không được thiết lập

Sự kiện bản thân nó vẫn được kích hoạt và event.loaded vẫn được phổ biến. Tuy nhiên, Chrome đang giải nén nội dung gzip'd khi đang di chuyển và (hôm nay) đặt loaded thành độ dài giải nén kết quả, chứ không phải là chiều dài được truyền. Không thể so sánh giá trị này với giá trị của tiêu đề Content-Length, vì đó là độ dài của nội dung được nén, vì vậy loaded sẽ trở nên lớn hơn độ dài nội dung.

Tốt nhất bạn có thể giả định một số yếu tố nén để so sánh loaded với Content-Length hoặc làm cho máy chủ thêm một số tiêu đề tùy chỉnh để cung cấp độ dài ban đầu hoặc hệ số nén thực, giả sử giải mã on-the-fly của Chrome sẽ không thay đổi.

Tôi không biết Chrome làm gì cho các giá trị khác cho Content-Encoding.

+0

Ít nhất: Tôi giả sử giá trị 'event.loaded' là kích thước giải nén (thay vì độ dài được truyền) không liên quan đến https: //crbug.com/763700 ... – Arjan

Các vấn đề liên quan