Tại sao httpClient BaseAddress không hoạt động?


299

Hãy xem xét đoạn mã sau, trong đó BaseAddressxác định đường dẫn URI một phần.

using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    client.BaseAddress = new Uri("http://something.com/api");
    var response = await client.GetAsync("/resource/7");
}

Tôi hy vọng điều này sẽ thực hiện một GETyêu cầu http://something.com/api/resource/7. Nhưng nó không.

Sau một số tìm kiếm, tôi tìm thấy câu hỏi và câu trả lời này: HttpClient với BaseAddress . Đề nghị là đặt /vào cuối của BaseAddress.

using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    client.BaseAddress = new Uri("http://something.com/api/");
    var response = await client.GetAsync("/resource/7");
}

Nó vẫn không hoạt động. Đây là tài liệu: HttpClient.BaseAddress Chuyện gì đang xảy ra ở đây?


Bản sao có thể có của HTTPClient với BaseAddress
George Lanetz

@ ГеоргиЛЛее Tôi đã viết câu hỏi này một cách cụ thể bởi vì câu hỏi khác không được viết theo cách mà những người có cùng vấn đề có thể khám phá được và tôi đã viết câu trả lời ở đây vì câu trả lời ở đó đã bỏ qua một điểm quan trọng.
Timothy Shields

nhưng câu hỏi này được hỏi sau
George Lanetz

2
@ Георгииее Thông thường câu hỏi "kinh điển" nhất là câu hỏi nhận được các bản sao trỏ đến nó. Câu hỏi khác là về một vấn đề duy nhất mà người dùng gặp phải thay vì đọc như Câu hỏi thường gặp.
Timothy Shields

2
@ ГеоргийЛ mô tả cũng chú ý Tôi tham khảo câu hỏi khác trong câu hỏi này và tôi giải thích tại sao câu hỏi và câu trả lời khác không đủ để giải quyết vấn đề.
Timothy Shields

Câu trả lời:


719

Nó chỉ ra rằng, trong số bốn hoán vị có thể bao gồm hoặc loại trừ dấu gạch chéo hoặc dấu gạch chéo về phía trước trên BaseAddressvà URI tương đối được truyền cho GetAsyncphương thức - hoặc bất kỳ phương pháp nào khác HttpClient- chỉ một phương pháp hoán vị hoạt động. Bạn phải đặt dấu gạch chéo ở cuối BaseAddressvà bạn không được đặt dấu gạch chéo ở đầu URI tương đối của mình, như trong ví dụ sau.

using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    client.BaseAddress = new Uri("http://something.com/api/");
    var response = await client.GetAsync("resource/7");
}

Mặc dù tôi đã trả lời câu hỏi của riêng mình, tôi nghĩ rằng tôi sẽ đóng góp giải pháp ở đây vì một lần nữa, hành vi không thân thiện này không có giấy tờ. Đồng nghiệp của tôi và tôi đã dành phần lớn thời gian trong ngày để cố gắng khắc phục một vấn đề mà cuối cùng là do sự kỳ quặc này HttpClient.


4
Cảm ơn bạn. Điều đó đã giải quyết một vấn đề mà tôi đã đấu tranh trong hầu hết hai ngày nay, giữa việc chuyển sang Azure, trở lại IIS và trở lại IIS Express, trong đó hầu hết bỏ qua các dấu gạch chéo bị đặt sai hoặc thêm. Khi được đặt trong lớp cơ sở của tôi RestClient, nó gần như vô hình và không có sự chú ý nào cả, và tôi chưa bao giờ thấy url đầy đủ tại các điểm dừng của mình, v.v.
ProfK

43
Tôi có thể xác nhận rằng sự kỳ lạ này (và cách khắc phục này) vẫn có liên quan trong .NET Core. Cảm ơn vì đã giảm Timothy kéo tóc của tôi.
Nate Barbettini

8
Điều này là do không có dấu gạch chéo khi nó xây dựng các yêu cầu, nó sẽ bỏ phần cuối cùng. Vì vậy, nó đạt một cái gì đó.com / resource / 7 . Nếu bạn đặt địa chỉ cơ sở là một cái gì đó / com (không quan trọng nếu có hoặc không có dấu gạch chéo) thì cũng không thành vấn đề nếu bạn đặt dấu gạch chéo ở đầu api / resource / 7. Không có dấu gạch chéo, phần cuối của địa chỉ cơ sở được xử lý như một tệp và bị hủy khi yêu cầu phình ra.
Piotr Perak

12
Đây không phải là trực tiếp giải quyết các câu hỏi ban đầu nhưng có liên quan. Trên mỗi Mircosoft, một phiên bản của HTTPClient () phải được gán cho một biến tĩnh và được sử dụng lại ( docs.microsoft.com/en-us/aspnet/web-api/overview/advified/ trộm - Creating a new HttpClient instance per request can exhaust the available sockets). Vì vậy, bạn nên xem xét loại bỏ bằng cách sử dụng ().
sanmcp

6
Chỉ là một thực hiện khủng khiếp. Tại sao họ không sửa cái này?
timmkrause

55

Độ phân giải tham chiếu được mô tả bởi RFC 3986 Mã định danh tài nguyên đồng nhất (URI): Cú pháp chung . Và đó chính xác là cách nó hoạt động. Để duy trì đường dẫn URI cơ sở, bạn cần thêm dấu gạch chéo ở cuối URI cơ sở và xóa dấu gạch chéo ở đầu URI tương đối.

Nếu URI cơ sở chứa đường dẫn không trống, quy trình hợp nhất sẽ loại bỏ phần cuối cùng (sau cùng /). Phần có liên quan :

5.2.3. Hợp nhất đường dẫn

Mã giả ở trên đề cập đến một thói quen "hợp nhất" để hợp nhất một tham chiếu đường dẫn tương đối với đường dẫn của URI cơ sở. Điều này được thực hiện như sau:

  • Nếu URI cơ sở có thành phần quyền hạn được xác định và đường dẫn trống, thì trả về một chuỗi bao gồm "/" được nối với đường dẫn của tham chiếu; nếu không thì

  • trả về một chuỗi bao gồm thành phần đường dẫn của tham chiếu được nối với tất cả trừ đoạn cuối của đường dẫn URI cơ sở (nghĩa là loại trừ bất kỳ ký tự nào sau "/" bên phải nhất trong đường dẫn URI cơ sở hoặc loại trừ toàn bộ đường dẫn URI cơ sở nếu nó không chứa bất kỳ ký tự "/" nào).

Nếu URI tương đối bắt đầu bằng dấu gạch chéo, nó được gọi là URI tương đối đường dẫn tuyệt đối. Trong trường hợp này, thủ tục hợp nhất bỏ qua tất cả đường dẫn URI cơ sở. Để biết thêm thông tin kiểm tra 5.2.2. Chuyển đổi phần Tài liệu tham khảo .


3
Tốt nhưng các thư viện máy khách như httpClient có nghĩa vụ bảo vệ chúng ta khỏi các chi tiết triển khai bí truyền như thế này.
Jamie Ide

-1

Gặp vấn đề với HTTPClient, ngay cả với các đề xuất vẫn không thể xác thực được. Hóa ra tôi cần một dấu '/' trong đường dẫn tương đối của mình.

I E

var result = await _client.GetStringAsync(_awxUrl + "api/v2/inventories/?name=" + inventoryName);
var result = await _client.PostAsJsonAsync(_awxUrl + "api/v2/job_templates/" + templateId+"/launch/" , new {
                inventory = inventoryId
            });

-6

Ngoài ra - không sử dụng BaseAddresstất cả. Đặt toàn bộ URL vào GetAsync()


33
Không trả lời câu hỏi nào.
Archibald

7
BaseAddress giảm tiếng ồn. Để mắt tôi nào. :)
MetalMikester

2
Tôi sẽ không đồng ý với những bình luận tiêu cực. Tôi đã dành 2 ngày để tìm hiểu lý do tại sao các cuộc gọi httpClient của tôi hoạt động trên Dev PC của tôi nhưng lại bị hỏng trên máy chủ. Oddly Powershell hoạt động nhưng .net thì không. Tôi đã sử dụng .SendAsyc. Sau đó tôi phát hiện ra rằng .GetAsyc hoạt động. Điều này dẫn tôi xuống một con đường khác và cuối cùng ở đây. Thêm hoặc xóa / giữa Địa chỉ cơ sở và URL tương đối không làm gì cả. Vẫn gặp lỗi 404 .... tuy nhiên khi tôi không đặt Địa chỉ cơ sở và đặt toàn bộ đường dẫn vào Relative .. nó đã hoạt động! Một lần nữa, đây là với .SendAsync nhưng đã có 2 ngày tôi sẽ không bao giờ quay lại!
da_jokker
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.