问题描述
亲爱的读者,
对于一个项目,我需要向公众公开第三方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();
}
}
推荐答案
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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!