Проблема заключается в получении URL-адреса из запроса Нэнси, а не в получении данных с HttpClient
.
Я предполагаю, что вы отправляете запрос Нэнси, например:
http://localhost/?url=...
следовательно, для Facebook это будет:
http://localhost/?url=https://scontent.xx.fbcdn.net/v/t1.0-1/c15.0.50.50/p50x50/10354686_10150004552801856_220367501106153455_n.2=oh=6c5o1f82cd8a32f589AAD2F
но для этого URL-адрес string url = Request.Query["url"].Value.ToString();
неполный и отсутствует последняя часть (& oe = 589AAD2F), поэтому сервер отвечает «Запрещено».
![введите описание изображения здесь](https://i.stack.imgur.com/QuoTr.png)
Вот простое изменение, демонстрирующее проблему:
private async Task<Response> GetResult(dynamic parameters, CancellationToken ct)
{
var client = new HttpClient();
var req = Request.Url.ToString();
var queryStart = req.IndexOf("url=");
if (queryStart == -1)
return Nancy.HttpStatusCode.BadRequest;
var url = req.Substring(queryStart + 4);
if (string.IsNullOrEmpty(url))
return Nancy.HttpStatusCode.BadRequest;
client.DefaultRequestHeaders.Add("Access-Control-Allow-Origin", "*");
client.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36");
client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, sdch, br");
client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
var response = await client.GetAsync(url, ct);
ct.ThrowIfCancellationRequested();
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.OK:
var stream = await response.Content.ReadAsStreamAsync();
return Response.FromStream(stream, response.Content.Headers.ContentType != null
? response.Content.Headers.ContentType.ToString()
: "application/octet-stream");
default:
return Response.AsText("\nError " + response.StatusCode);
}
}
Решение
На самом деле мы можем закодировать URL-адрес перед его отправкой, и Нэнси автоматически декодирует URL-адрес для нас, поэтому нет необходимости что-либо менять на стороне сервера.
Вот пример ссылки, созданной с использованием HttpUtility.UrlEncode
, примененного к
https ://scontent.xx.fbcdn.net/v/t1.0-1/c15.0.50.50/p50x50/10354686_10150004552801856_220367501106153455_n.jpg?oh=6c801f82cd5a32fd6e5a4258ce0oe2a4294a
Результат:
HTTPS% 3a% 2f% 2fscontent.xx.fbcdn.net% 2fv% 2ft1.0-1% 2fc15.0.50.50% 2fp50x50% 2f10354686_10150004552801856_220367501106153455_n.jpg% 3foh% 3d6c801f82cd5a32fd6e5a4258ce00a314% 26oe% 3d589AAD2F EM>
и фактический запрос для этой конкретной ссылки будет:
http://localhost:9876/?url=https%3a%2f%2fscontent.xx.fbcdn.net%2fv%2ft1.0-1%2fc15.0.50.50%2fp50x50%2f10354686_10150004552801856_220367501106_n.jpg%553foh%3d6c801f82cd5a32fd6e5a4258ce00a314%26oe%3d589AAD2F
Альтернативное решение
Я лично предпочитаю POST вместо GET в этой ситуации, так что вот оно:
public class ReverseProxyController : NancyModule
{
class ProxyRequest
{
public string Url { get; set; }
}
public ReverseProxyController()
{
Post["/", true] = async (parameters, ct) =>
{
var result = await GetResult(parameters, ct);
return result;
};
}
private async Task<Response> GetResult(dynamic parameters, CancellationToken ct)
{
var pReq = this.Bind<ProxyRequest>();
var url = pReq.Url;
if (string.IsNullOrEmpty(url))
return null;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Access-Control-Allow-Origin", "*");
client.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36");
client.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1");
client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, sdch, br");
client.DefaultRequestHeaders.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
var response = await client.GetAsync(url, ct);
ct.ThrowIfCancellationRequested();
switch (response.StatusCode)
{
case System.Net.HttpStatusCode.OK:
var stream = await response.Content.ReadAsStreamAsync();
return Response.FromStream(stream, response.Content.Headers.ContentType != null
? response.Content.Headers.ContentType.ToString()
: "application/octet-stream");
default:
return Response.AsText("\nError " + response.StatusCode);
}
}
}
person
user3473830
schedule
31.10.2016
Response.FromStream
иResponse.AsText
из какой библиотеки? Или что они делают? - person Jim   schedule 29.10.2016http
, но не работает дляhttps
, что, я думаю, связано с сертификатом. Это был простой тест только с URL-адресом. никаких других заголовков. получить ответ 200 OK - person Nkosi   schedule 31.10.2016http
вместоhttps
. https выдает ошибку сертификата. простой асинхронный модульный тест с URL-адресом вызова httpclient. - person Nkosi   schedule 31.10.2016