2011-02-01 16 views
9

Tôi đang gặp rắc rối mã hóa URL đến một URI:URL để mã hóa URI thay đổi một "% 3D" vào "% 253D"

mUrl = "A string url that needs to be encoded for use in a new HttpGet()"; 
URL url = new URL(mUrl); 
URI uri = new URI(url.getProtocol(), url.getAuthority(), url.getPath(), 
    url.getQuery(), null); 

này không làm những gì tôi mong đợi cho các URL sau:

Đi qua trong String:

http://m.bloomingdales.com/img?url=http%3A%2F%2Fimages.bloomingdales.com%2Fis%2Fimage%2FBLM%2Fproducts%2F3%2Foptimized%2F1140443_fpx.tif%3Fwid%3D52%26qlt%3D90%2C0%26layer%3Dcomp%26op_sharpen%3D0%26resMode%3Dsharp2%26op_usm%3D0.7%2C1.0%2C0.5%2C0%26fmt%3Djpeg&ttl=30d

Comes ra như:

http://m.bloomingdales.com/img?url=http%253A%252F%252Fimages.bloomingdales.com%252Fis%252Fimage%252FBLM%252Fproducts%252F3%252Foptimized%252F1140443_fpx.tif%253Fwid%253D52%2526qlt%253D90%252C0%2526layer%253Dcomp%2526op_sharpen%253D0%2526resMode%253Dsharp2%2526op_usm%253D0.7%252C1.0%252C0.5%252C0%2526fmt%253Djpeg&ttl=30d

Đó là bị hỏng. Ví dụ: %3D được chuyển thành %253D Có vẻ như bạn đang làm điều gì đó bí ẩn với% đã có trong chuỗi.

Điều gì đang xảy ra và tôi đang làm gì sai ở đây?

Trả lời

22

Trước tiên, bạn đặt chuỗi (đã thoát) vào lớp URL. Điều đó không thoát khỏi bất cứ điều gì. Sau đó, bạn đang kéo ra các phần của URL, trả về chúng mà không cần xử lý thêm (vì vậy - chúng vẫn bị thoát vì chúng đã được thoát khi bạn đặt chúng vào). Cuối cùng, bạn đang đặt các phần vào lớp URI, sử dụng multi-argument constructor. Hàm khởi tạo này được chỉ định là mã hóa các thành phần URI bằng cách sử dụng phần trăm.

Do đó, trong bước cuối cùng này, ví dụ: ":" trở thành "%3A" (tốt) và "%3A" trở thành "%253A" (không hợp lệ). Vì bạn đang đặt các URL đã được mã hóa *, bạn không muốn mã hóa lại chúng.

Do đó, single-argument constructor của URI là bạn của bạn. Nó không thoát khỏi bất cứ điều gì, và yêu cầu bạn vượt qua một chuỗi thoát trước. Do đó, bạn không cần phải URL tại tất cả:

mUrl = "A string url is already percent-encoded for use in a new HttpGet()"; 
URI uri = new URI(mUrl); 

* Vấn đề duy nhất là nếu URL của bạn là đôi khi không phần trăm mã hóa, và đôi khi họ đang có. Sau đó, bạn có một vấn đề lớn hơn. Bạn cần phải quyết định xem chương trình của bạn có bắt đầu bằng URL luôn được mã hóa hoặc chương trình cần được mã hóa hay không.

Lưu ý rằng có không có điều như vậy làm URL đầy đủ không được mã hóa theo phần trăm. Ví dụ: bạn không thể lấy URL đầy đủ "http://example.com/bob&co" và bằng cách nào đó biến URL đó thành URL được mã hóa đúng "http://example.com/bob%26co" - cách bạn có thể cho biết sự khác biệt giữa cú pháp (không nên thoát) và các ký tự (nên)? Đây là lý do tại sao dạng đối số đơn lẻ là URI yêu cầu các chuỗi đã được thoát. Nếu bạn có các chuỗi chưa thoát, bạn cần mã hóa phần trăm chúng trước khi chèn chúng vào cú pháp URL đầy đủ và đó là những gì mà hàm tạo đa đối số của URI giúp bạn thực hiện.

Chỉnh sửa: Tôi bỏ lỡ thực tế là mã gốc loại bỏ đoạn.Nếu bạn muốn xóa đoạn (hoặc bất kỳ phần nào khác) của URL, bạn có thể tạo URI như trên, sau đó kéo tất cả các phần ra theo yêu cầu (chúng sẽ được giải mã thành chuỗi thông thường), sau đó chuyển chúng trở lại các nhà xây dựng URI đa đối số (nơi họ sẽ tái mã hóa như các thành phần URI):

uri = new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), 
       uri.getPath(), uri.getQuery(), null) // Remove fragment 
+0

Điều đó có ý nghĩa, cảm ơn bạn đã viết. Các url đang được lấy từ mã html, vì vậy tôi cho rằng chúng sẽ phải được mã hóa rồi? Một trong những lý do tôi đã sử dụng URL và hàm tạo đa đối số là vì tôi cần loại bỏ đoạn (nếu có) khỏi URI. Có cách nào tôi có thể làm điều này mà không cần mã hóa đôi? Sẽ có một cái gì đó như String urlMinusFragment = url.getProtocol() + ": //" + url.getAuthority() + url.getPath() + "?" + url.getQuery(); Hãy an toàn để làm gì? Sau đó, tôi có thể ném chuỗi đó vào hàm tạo URI (chuỗi) mới. Cảm ơn một lần nữa. – cottonBallPaws

+0

Nếu bạn tách URL ra khỏi thuộc tính 'href' trong HTML, thì chúng phải luôn được mã hóa đúng (nếu không, thì HTML không hợp lệ, vì vậy bạn có thể coi đó là lỗi). Kỹ thuật loại bỏ đoạn có vẻ OK nhưng bạn đang xây dựng một URL theo cách thủ công (có thư viện). Tôi sẽ sử dụng lớp URI. Giống như URL, URI có các thành phần getters, nhưng chúng trả về các chuỗi * được giải mã * mà an toàn để đưa trở lại vào URI. Vì vậy, URI (uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), uri.getPath(), uri.getQuery(), null) 'nên hoạt động. – mgiuca

+0

rực rỡ, hoạt động hoàn hảo. Cảm ơn – cottonBallPaws

4

Lớp URL không giải mã% -sequences khi phân tích cú pháp URL, nhưng lớp URI mã hóa chúng (lại). Sử dụng URI để phân tích cú pháp chuỗi URL.

Javadocs:

http://download.oracle.com/javase/6/docs/api/java/net/URL.html

Lớp URL không tự mã hóa hoặc giải mã bất kỳ thành phần URL theo cơ chế thoát được định nghĩa trong RFC2396. Đó là trách nhiệm của người gọi để mã hóa bất kỳ trường nào, cần phải được thoát trước khi gọi URL, và cũng để giải mã bất kỳ trường thoát nào, được trả lại từ URL. Hơn nữa, vì URL không có kiến ​​thức về thoát URL, nó không nhận ra sự tương đương giữa dạng được mã hóa hoặc giải mã của cùng một URL. Ví dụ, hai URL:

http://foo.com/hello world/ and http://foo.com/hello%20world 

sẽ được coi là không bình đẳng với nhau. Lưu ý, lớp URI thực hiện việc thoát khỏi các trường thành phần của nó trong một số trường hợp nhất định.

Cách khuyến khích để quản lý mã hóa và giải mã URL là sử dụng URI, và để chuyển đổi giữa hai loại cổ phiếu này sử dụng toURI() và URI.toURL().

-2

Điều đang xảy ra ở đây là các dấu hiệu % từ URL đầu tiên đang được thoát, nghĩa là chúng được chuyển thành %25 ở đầu ra. Bạn cần phải đề phòng tại chỗ để tập lệnh của bạn chỉ thoát khỏi các ký tự chữ và số, cũng như một số ký hiệu - nhưng không phải là các ký tự đã thoát.

Đây là một số ký tự cần thoát:

< 
> 
" 
! 
# 
$ 
' 
(
) 
* 
, 
- 
. 
/
: 
; 
@ 
[ 
\ 
] 
^ 
_ 
` 
{ 
| 
} 
~ 

Phần còn lại, như =, %, và &, và ký tự chữ, thì không.

+1

Không, đó không phải là cách đúng đắn để suy nghĩ về nó cả. Bạn đã có URL được mã hóa phần trăm hoàn chỉnh. Mọi ký tự cần được mã hóa đều được mã hóa. Nếu lời khuyên của bạn không phải là mã hóa các dấu "%", thì chắc chắn, "% 3A" sẽ giữ nguyên "% 3A" thay vì trở thành "% 253A", nhưng bạn cũng sẽ mã hóa quá mức các phần tử cú pháp khác. Ví dụ, "x = 4 & y = 7" (có nghĩa là x là "4" và y là "7") sẽ trở thành "x = 4% 26y = 7" (có nghĩa là x là "4 & y = 7"). Cố gắng để có được đúng bộ ký tự nghĩa là các trường hợp phổ biến hơn sẽ hoạt động và bạn sẽ có ít trường hợp lỗi hơn, nhưng bạn sẽ không loại bỏ chúng. – mgiuca

+0

Ngoài ra, bạn đã liệt kê "=" và "%" khi cả hai đều cần thoát và không cần thoát. – mgiuca

+0

Cảm ơn bạn đã chỉ ra các lỗi đó. Ấn tượng của tôi về những gì đã sai với mã của littleFluffyKitty là một số ký tự được mã hóa đôi. – pop850

4

% 3d means->=(Equal)

Một nd

% 253D ->=(Equal) 6hex thập phân (byte) 3D

% 253D hex chỉ cho CGI: % 3D

+0

% 3d ở định dạng UTF-8? Làm thế nào chúng ta có thể giải mã String với các ký tự% 3D,% 26 etc? – Kushal