如何构建网络“代理”用于API [英] How do I build web "proxy" for an API

查看:92
本文介绍了如何构建网络“代理”用于API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

亲爱的读者,



对于一个项目,我需要向公众公开第三方API。为此,我想我可以轻松获取传入请求,将其重新路由到API,获取响应并向客户端发送响应。理论上相当简单的概念,但不知何故有问题。部分代理工作,但当我通过浏览器访问代理时,一些数据看起来相同,而其他数据看起来不同(json而不是XML),有些我甚至无法显示(gzip chunked)。



请帮忙(听起来非常绝望,我是),
$ b $bRémySamulski



我尝试过的:



我已经构建了一个将接收请求的webform,构建一个新的HttpRequestMessage并通过HttpClient将其发送到API。我收到HttpResponseMessage,提取内容(这里GZIP部分出错)并通过HttpResponse发回。下面的代码是使用在线OData API进行复制所需的全部代码。以下URL似乎在浏览器中通过代理或直接(在漂亮的XML表示中)类似:

/ Proxy2 /

/ Proxy2 / $ metadata



但这些给出了不同的结果:

/ Proxy2 / Customers(给出JSON但是直接以纯ASCII格式提供XML,没有XML表示)

/ Proxy2 / Employees(给出错误但直接以纯ASCII格式提供XML)



Dear readers,

For a project I need to expose a third party API partly to the public. To do this I thought I could easily get in incoming request, reroute it to the API, get response back and deliver response to the client. Pretty simple concept in theory, but somehow problematic. Partly the proxy works but when I access the proxy via browser some data look the same while others look differently (json instead of XML) and some I can't even display (gzip chunked).

Please help (sounds really desperate and I am),
Rémy Samulski

What I have tried:

I have build a webform that will take the request, build a new HttpRequestMessage and send it via HttpClient to the API. I receive the HttpResponseMessage, pull out the content (here the GZIP part goes wrong) and send it back through the HttpResponse. The code below is all that is needed to replicate using online OData API. The following URL's seem to work similar in browser through Proxy or directly (in nice XML representation):
/Proxy2/
/Proxy2/$metadata

But these give different results:
/Proxy2/Customers (gives JSON but directly gives XML in plain ASCII, no XML representation)
/Proxy2/Employees (gives error but directly gives XML in plain ASCII)

public class Global : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        GlobalConfiguration.Configure(WebApiConfig.Register);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if ((Request.RawUrl.ToLower() + "/").StartsWith("/proxy2/") == true)
        {
            Context.RewritePath("~/_Proxy2.aspx", false);
        }
    }
}




public partial class _Proxy2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string url = Request.RawUrl.Replace("/Proxy2", "").TrimStart('/');

        System.Net.Http.HttpRequestMessage httpRequestMessage =
            new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, "https://services.odata.org/V4/Northwind/Northwind.svc/" + url);
        Business.Http.AddHeaders(Request, httpRequestMessage);

        System.Net.Http.HttpResponseMessage httpResponseMessage;
        System.IO.Stream contentStream;
        using (System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient())
        {
            httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
            contentStream = httpResponseMessage.Content.ReadAsStreamAsync().Result;
        }

        Response.Clear();
        Response.ClearHeaders();
        Business.Http.AddHeaders(Response, httpResponseMessage);

        contentStream.CopyTo(Response.OutputStream);
        Response.End();
    }
}




public class Http
{
    public static void AddHeaders(HttpRequest httpRequest, System.Net.Http.HttpRequestMessage httpRequestMessage)
    {
        foreach (string key in httpRequest.Headers.Keys)
        {
            string values = httpRequest.Headers[key];
            System.Diagnostics.Debug.WriteLine("Request " + key + " : " + values);
            switch (key)
            {
                case "Host":
                    //Removed due to SSL problems
                    break;
                default:
                    bool found = false;
                    IEnumerable<string> valuesCurrent;
                    if (httpRequestMessage.Headers.TryGetValues(key, out valuesCurrent) == true)
                    {
                        foreach (var item in valuesCurrent)
                        {
                            if (item.ToLower() == values.ToLower())
                            {
                                found = true;
                                break;
                            }
                        }
                    }
                    if (found == false)
                    {
                        httpRequestMessage.Headers.Add(key, values);
                    }
                    break;
            }
        }
        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpRequest);
        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpRequestMessage);
        System.Diagnostics.Debug.WriteLine("");
    }

    public static void AddHeaders(HttpResponse httpResponse, System.Net.Http.HttpResponseMessage httpResponseMessage)
    {
        httpResponse.CacheControl = httpResponseMessage.Headers.CacheControl.ToString();

        foreach (KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> item in httpResponseMessage.Headers)
        {
            AddHeaders(httpResponse, item);
        }
        System.Diagnostics.Debug.WriteLine("");
        foreach (KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> item in httpResponseMessage.Content.Headers)
        {
            AddHeaders(httpResponse, item);
        }

        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpResponse);
        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpResponseMessage);
        System.Diagnostics.Debug.WriteLine("");
    }

    private static void AddHeaders(HttpResponse httpResponse, KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> keyValuePair)
    {
        string key = keyValuePair.Key;
        string values = "";
        foreach (string stringValue in keyValuePair.Value)
        {
            if (values.Contains("," + stringValue) == false)
            {
                values += "," + stringValue;
            }
        }
        values = values.Trim(',');
        System.Diagnostics.Debug.WriteLine("Response " + key + " : " + values);
        switch (key)
        {
            case "Content-Type":
                httpResponse.ContentType = values;
                break;
            default:
                httpResponse.Headers.Add(key, values);
                break;
        }
    }
}




public class Reflection
{
    public static void DebugShowAllProperties(object obj)
    {
        var properties = GetProperties(obj);

        System.Diagnostics.Debug.WriteLine(obj.GetType().FullName);

        foreach (var p in properties)
        {
            string name = p.Name;
            string value = "NULL";
            try
            {
                object valueObject = p.GetValue(obj, null);

                if (valueObject != null)
                {
                    value = valueObject.ToString();
                }
            }
            catch
            {

            }
            System.Diagnostics.Debug.WriteLine(name + " : " + value);
        }

    }

    private static System.Reflection.PropertyInfo[] GetProperties(object obj)
    {
        return obj.GetType().GetProperties();
    }
}

推荐答案

元数据



但是这些给出了不同的结果:

/ Proxy2 / Customers(给出JSON但是直接以纯ASCII格式提供XML,没有XML表示)

/ Proxy2 / Employees (给出错误,但直接以纯ASCII格式提供XML)



metadata

But these give different results:
/Proxy2/Customers (gives JSON but directly gives XML in plain ASCII, no XML representation)
/Proxy2/Employees (gives error but directly gives XML in plain ASCII)

public class Global : HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        GlobalConfiguration.Configure(WebApiConfig.Register);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }

    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        if ((Request.RawUrl.ToLower() + "/").StartsWith("/proxy2/") == true)
        {
            Context.RewritePath("~/_Proxy2.aspx", false);
        }
    }
}




public partial class _Proxy2 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string url = Request.RawUrl.Replace("/Proxy2", "").TrimStart('/');

        System.Net.Http.HttpRequestMessage httpRequestMessage =
            new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, "https://services.odata.org/V4/Northwind/Northwind.svc/" + url);
        Business.Http.AddHeaders(Request, httpRequestMessage);

        System.Net.Http.HttpResponseMessage httpResponseMessage;
        System.IO.Stream contentStream;
        using (System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient())
        {
            httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
            contentStream = httpResponseMessage.Content.ReadAsStreamAsync().Result;
        }

        Response.Clear();
        Response.ClearHeaders();
        Business.Http.AddHeaders(Response, httpResponseMessage);

        contentStream.CopyTo(Response.OutputStream);
        Response.End();
    }
}




public class Http
{
    public static void AddHeaders(HttpRequest httpRequest, System.Net.Http.HttpRequestMessage httpRequestMessage)
    {
        foreach (string key in httpRequest.Headers.Keys)
        {
            string values = httpRequest.Headers[key];
            System.Diagnostics.Debug.WriteLine("Request " + key + " : " + values);
            switch (key)
            {
                case "Host":
                    //Removed due to SSL problems
                    break;
                default:
                    bool found = false;
                    IEnumerable<string> valuesCurrent;
                    if (httpRequestMessage.Headers.TryGetValues(key, out valuesCurrent) == true)
                    {
                        foreach (var item in valuesCurrent)
                        {
                            if (item.ToLower() == values.ToLower())
                            {
                                found = true;
                                break;
                            }
                        }
                    }
                    if (found == false)
                    {
                        httpRequestMessage.Headers.Add(key, values);
                    }
                    break;
            }
        }
        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpRequest);
        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpRequestMessage);
        System.Diagnostics.Debug.WriteLine("");
    }

    public static void AddHeaders(HttpResponse httpResponse, System.Net.Http.HttpResponseMessage httpResponseMessage)
    {
        httpResponse.CacheControl = httpResponseMessage.Headers.CacheControl.ToString();

        foreach (KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> item in httpResponseMessage.Headers)
        {
            AddHeaders(httpResponse, item);
        }
        System.Diagnostics.Debug.WriteLine("");
        foreach (KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> item in httpResponseMessage.Content.Headers)
        {
            AddHeaders(httpResponse, item);
        }

        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpResponse);
        System.Diagnostics.Debug.WriteLine("");
        Business.Reflection.DebugShowAllProperties(httpResponseMessage);
        System.Diagnostics.Debug.WriteLine("");
    }

    private static void AddHeaders(HttpResponse httpResponse, KeyValuePair<string, System.Collections.Generic.IEnumerable<string>> keyValuePair)
    {
        string key = keyValuePair.Key;
        string values = "";
        foreach (string stringValue in keyValuePair.Value)
        {
            if (values.Contains("," + stringValue) == false)
            {
                values += "," + stringValue;
            }
        }
        values = values.Trim(',');
        System.Diagnostics.Debug.WriteLine("Response " + key + " : " + values);
        switch (key)
        {
            case "Content-Type":
                httpResponse.ContentType = values;
                break;
            default:
                httpResponse.Headers.Add(key, values);
                break;
        }
    }
}




public class Reflection
{
    public static void DebugShowAllProperties(object obj)
    {
        var properties = GetProperties(obj);

        System.Diagnostics.Debug.WriteLine(obj.GetType().FullName);

        foreach (var p in properties)
        {
            string name = p.Name;
            string value = "NULL";
            try
            {
                object valueObject = p.GetValue(obj, null);

                if (valueObject != null)
                {
                    value = valueObject.ToString();
                }
            }
            catch
            {

            }
            System.Diagnostics.Debug.WriteLine(name + " : " + value);
        }

    }

    private static System.Reflection.PropertyInfo[] GetProperties(object obj)
    {
        return obj.GetType().GetProperties();
    }
}


针对您的服务API运行Postman并查看它为您提供的内容。尝试准确复制代理生成的内容(具体查看HTTP标头)。您可以在Fiddler中验证这一点。您是否正在发送内容类型,如果是这样,它设置为什么?您是否在请求中发送了接受标头?你应该指定你想要的东西(Json / xml)。用邮递员测试。
Run Postman against your service API and see what it gives you. Try to duplicate exactly what your proxy is generating (look specifically at the HTTP headers). You can verify this in Fiddler. Are you sending content-type, and if so what is it set to? Are you sending an 'accept' header in the request? You should specify what you want back (Json/xml). Test this with postman.


这篇关于如何构建网络“代理”用于API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆