Ретрансляция запроса в asp.net (пересылка запроса)

У меня есть веб-приложение, которое взаимодействует между двумя разными веб-приложениями (один получатель и один отправитель, отправитель взаимодействует с моим приложением, а мое приложение взаимодействует с обоими).

Обычный сценарий заключается в том, что отправитель отправляет HttpRequest моему приложению, и я получаю его в HttpHandler. Это, в свою очередь, отправляет HttpContext в некоторую бизнес-логику, чтобы выполнить некоторые действия.

После того, как мои бизнес-классы закончили хранение данных (некоторые журналы и т. д.), я хочу передать тот же запрос со всеми заголовками, данными формы и т. д. в приложение-получатель. Это должно быть отправлено из класса, а не HttpHandler.

На самом деле вопрос в том, как я могу взять объект HttpContext и перенаправить/ретранслировать точно такой же запрос, только изменив URL-адрес с http://myserver.com/ на http://receiver.com.

Любые примеры кода в предпочтительном С# были бы замечательными!


person El Che    schedule 30.03.2009    source источник


Ответы (5)


У меня есть метод расширения на HttpResponseBase для копирования входящего запроса в исходящий запрос.

Использование:

    var externalRequest = (HttpWebRequest)WebRequest.Create("http://stackoverflow.com");
    this.Request.CopyTo(externalRequest);
    var externalResponse = (HttpWebResponse)externalRequest.GetResponse();

Источник:

/// <summary>
/// Copies all headers and content (except the URL) from an incoming to an outgoing
/// request.
/// </summary>
/// <param name="source">The request to copy from</param>
/// <param name="destination">The request to copy to</param>
public static void CopyTo(this HttpRequestBase source, HttpWebRequest destination)
{
    destination.Method = source.HttpMethod;

    // Copy unrestricted headers (including cookies, if any)
    foreach (var headerKey in source.Headers.AllKeys)
    {
        switch (headerKey)
        {
            case "Connection":
            case "Content-Length":
            case "Date":
            case "Expect":
            case "Host":
            case "If-Modified-Since":
            case "Range":
            case "Transfer-Encoding":
            case "Proxy-Connection":
                // Let IIS handle these
                break;

            case "Accept":
            case "Content-Type":
            case "Referer":
            case "User-Agent":
                // Restricted - copied below
                break;

            default:
                destination.Headers[headerKey] = source.Headers[headerKey];
                break;
        }
    }

    // Copy restricted headers
    if (source.AcceptTypes.Any())
    {
        destination.Accept = string.Join(",", source.AcceptTypes);
    }
    destination.ContentType = source.ContentType;
    destination.Referer = source.UrlReferrer.AbsoluteUri;
    destination.UserAgent = source.UserAgent;

    // Copy content (if content body is allowed)
    if (source.HttpMethod != "GET"
        && source.HttpMethod != "HEAD"
        && source.ContentLength > 0)
    {
        var destinationStream = destination.GetRequestStream();
        source.InputStream.CopyTo(destinationStream);
        destinationStream.Close();
    }
}
person diachedelic    schedule 20.09.2012
comment
источник.ВходнойПоток.Позиция = 0; требуется перед source.InputStream.CopyTo - person bfi; 20.10.2014
comment
Небольшое изменение, так как часть заголовков безопаснее и полнее: foreach (var headerKey in source.Headers.AllKeys) { if (!WebHeaderCollection.IsRestricted(headerKey)) { target.Headers[headerKey] = источник.Заголовки[headerKey]; } - person Nuno Rodrigues; 11.06.2015
comment
Копирование файла cookie с использованием заголовков, как вы предлагаете, не включает файл cookie в переадресованный запрос. - person johni; 15.08.2016

На самом деле, что-то вроде этого работало хорошо

HttpRequest original = context.Request;
HttpWebRequest newRequest = (HttpWebRequest)WebRequest.Create(newUrl);

newRequest .ContentType = original.ContentType;
newRequest .Method = original.HttpMethod;
newRequest .UserAgent = original.UserAgent;

byte[] originalStream = ReadToByteArray(original.InputStream, 1024);

Stream reqStream = newRequest .GetRequestStream();
reqStream.Write(originalStream, 0, originalStream.Length);
reqStream.Close();


newRequest .GetResponse();

редактировать: метод ReadToByteArray просто создает массив байтов из потока

person El Che    schedule 31.03.2009
comment
Как насчет параметров заголовка запроса и файлов cookie? - person Adrian Grigore; 08.03.2011
comment
Не нужно для моего контекста, но да, это тоже можно сделать - person El Che; 09.03.2011
comment
Я обобщил этот ответ ниже как метод расширения для копирования всех заголовков и файлов cookie. - person diachedelic; 26.09.2012
comment
В чем большая разница между этим подходом и использованием Server.Transfer()? - person Donald.Record; 09.11.2015
comment
@Donald.Record Server.transfer может работать только для сайтов, работающих на сервере в том же пуле приложений; вы не можете использовать Server.Transfer для отправки пользователя на внешний сайт. - person user1069816; 24.11.2015
comment
новый запрос .ContentType = original.ContentType; это создает проблему уязвимости безопасности при манипулировании заголовками в сканерах. - person vinodh; 12.10.2016

Вот хороший код ретрансляции в VB.NET с использованием MVC.

ГЛОБАЛ.ASAX.VB

Public Class MvcApplication
    Inherits System.Web.HttpApplication

    Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
        routes.MapRoute("Default", "{*s}", New With {.controller = "Home", .action = "Index"})
    End Sub

    Sub Application_Start()
        RegisterRoutes(RouteTable.Routes)
    End Sub
End Class

HomeController.vb

Option Explicit On
Option Strict On

Imports System.Net

<HandleError()> _
Public Class HomeController
    Inherits System.Web.Mvc.Controller

    Function Index(ByVal s As String) As ActionResult
        Server.ScriptTimeout = 60 * 60
        If Request.QueryString.ToString <> "" Then s = s + "?" + Request.QueryString.ToString
        Dim req As HttpWebRequest = CType(WebRequest.Create("http://stackoverflow.com/" + s), HttpWebRequest)
        req.AllowAutoRedirect = False
        req.Method = Request.HttpMethod
        req.Accept = Request.Headers("Accept")
        req.Referer = Request.Headers("Referer")
        req.UserAgent = Request.UserAgent
        For Each h In Request.Headers.AllKeys
            If Not (New String() {"Connection", "Accept", "Host", "User-Agent", "Referer"}).Contains(h) Then
                req.Headers.Add(h, Request.Headers(h))
            End If
        Next
        If Request.HttpMethod <> "GET" Then
            Using st = req.GetRequestStream
                StreamCopy(Request.InputStream, st)
            End Using
        End If
        Dim resp As WebResponse = Nothing
        Try
            Try
                resp = req.GetResponse()
            Catch ex As WebException
                resp = ex.Response
            End Try

            If resp IsNot Nothing Then
                Response.StatusCode = CType(resp, HttpWebResponse).StatusCode
                For Each h In resp.Headers.AllKeys
                    If Not (New String() {"Content-Type"}).Contains(h) Then
                        Response.AddHeader(h, resp.Headers(h))
                    End If
                Next
                Response.ContentType = resp.ContentType

                Using st = resp.GetResponseStream
                    StreamCopy(st, Response.OutputStream)
                End Using
            End If
        Finally
            If resp IsNot Nothing Then resp.Close()
        End Try
        Return Nothing
    End Function
    Sub StreamCopy(ByVal input As IO.Stream, ByVal output As IO.Stream)
        Dim buf(0 To 16383) As Byte
        Using br = New IO.BinaryReader(input)
            Using bw = New IO.BinaryWriter(output)
                Do
                    Dim rb = br.Read(buf, 0, buf.Length)
                    If rb = 0 Then Exit Do
                    bw.Write(buf, 0, rb)
                Loop
            End Using
        End Using
    End Sub
End Class
person Hafthor    schedule 17.08.2009

HttpContext включает свойство Request, которое, в свою очередь, содержит коллекцию заголовков. Это должна быть вся необходимая информация.

person John Saunders    schedule 30.03.2009
comment
HttpWebRequest relayingRequest = (HttpWebRequest)WebRequest.Create(relayUrl); relayingRequest.Headers.Add(context.Request.Headers); Это не работает - мне также нужны параметры, httpmethod и т. д. Запрос должен быть идентичным... - person El Che; 30.03.2009
comment
Все это есть в HttpContext.Request почти по определению. Учтите, что именно так страница или другой обработчик узнает, что делать. В Context.Request также есть свойство QueryString и Form. Посмотрите свойства, и вы увидите. - person John Saunders; 30.03.2009
comment
Да, я знаю, что они все там, но помните, что context.Request — это не System.Net.HttpWebRequest, а System.Web.HttpRequest. Я не уверен, что это так же просто, как просто искать реквизиты и вставлять их в новый запрос. - person El Che; 30.03.2009
comment
Я уверен. Почему вы ищете что-то более сложное? Посмотрите, попробуйте и убедитесь. - person John Saunders; 30.03.2009
comment
Я проверю больше завтра. Кажется, мне нужно прочитать входной поток из исходного запроса и записать его в новый. Также мне нужно скопировать некоторые свойства, как вы говорите. Странно, что нет способа дублировать запрос без таких хлопот. - person El Che; 30.03.2009
comment
Это не то, что люди должны делать очень часто. Это чаще всего делается на более низком уровне сетевой инфраструктуры. - person John Saunders; 30.03.2009

возможно что-то вроде:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("www.testing.test");
request.Headers = (WebHeaderCollection)Request.Headers;

Затем вызовите ответ на получение

HttpWebResponse response  = (HttpWebResponse)request.GetResponse();

Он будет иметь те же заголовки HTTP, что и исходный запрос.

person dkarzon    schedule 31.03.2009
comment
Невозможно привести объект типа «System.Web.HttpHeaderCollection» к типу «System.Net.WebHeaderCollection». - person El Che; 31.03.2009