代码之家  ›  专栏  ›  技术社区  ›  BeniaminoBaggins

在ASP.Net Core 7应用程序中使用Yarp编写CORS任意位置代理服务器

  •  0
  • BeniaminoBaggins  · 技术社区  · 1 年前

    我正在调用Flutter的googleapi网络服务。它可以在Android和iOS上运行,然而,在网络中,它会导致CORS问题,因为谷歌API不应该从浏览器中调用。

    Someone has found a workaround 要将其添加到GET HTTP请求URL的开头,请执行以下操作:

    https://cors-anywhere.herokuapp.com/

    因此完整的URL是 'https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api/place/autocomplete/json' 然后在其末尾添加一些查询参数。

    软件包创建者还表示 we need to use a proxy server 。我认为Heroku解决方案在可接收的请求数量方面受到严重限制。

    我可以使用现有的ASP.NET Core 7应用程序实现这一点吗?

    我正在尝试使用 Yarp

    我已将其添加到appsettings.json中:

      "ReverseProxy": {
        "Routes": {
          "route1": {
            "ClusterId": "cluster1",
            "Match": {
              "Path": "/googlemapswebservice"
            }
          }
        },
        "Clusters": {
          "cluster1": {
            "Destinations": {
              "destination1": {
                "Address": "https://maps.googleapis.com/maps/api/place/autocomplete/json/"
              }
            }
          }
        }
      },
    

    在…内 ConfigureServices() :

    services.AddReverseProxy().LoadFromConfig(Configuration.GetSection("ReverseProxy")); 
    

    在…内 Configure() :

    app.UseEndpoints(endpoints => 
    { 
        endpoints.MapControllers(); 
        endpoints.MapReverseProxy(); 
    }); 
    

    编辑:我怀疑在使用Yarp时,我们甚至不应该创建控制器端点,这意味着我应该删除下面的代码。

    网络控制器;现在,这是我不知道在Yarp的背景下我在做什么的主要部分:

    [Route("[controller]")]
    [ApiController]
    public class GoogleMapsWebServiceController : ControllerBase
    {
        private readonly VepoContext _context;
        protected readonly ExtendedVepoContext extendedContext;
    
        public GoogleMapsWebServiceController(
            VepoContext context,
            ExtendedVepoContext extendedContext)
        {
            _context = context;
            this.extendedContext = extendedContext;
        }
    
        [HttpGet]
        [AllowAnonymous]
        public async Task<OkResult> GoogleMapsWebService()
        {
            return await Task.FromResult(Ok());
        }
    }
    

    当我向此处发出http请求时:

    http://192.xxx.x.xx:5002/googlemapswebservice

    我可以达到我的端点(不过我不认为它会被转发到googleapi,而是一步一步)。

    当我向此处发出http请求时:

    http://192.xxx.x.xx:5002/googlemapswebservice/https://maps.googleapis.com/maps/api/place/autocomplete/json?input=a&location=-36.8508827%2C174.7644881&radius=500&types=establishment&key=xxxxxxxxxxxxxxxxx

    我似乎在OPTIONS http请求上达到了我的端点,因为它的响应是204 No Content。然后在同一个带有GET http请求的url上,它会以404 Not Found作为响应,那么它真的达到了我的端点吗?

    我猜,默认情况下,当您将转发http地址附加到url中的初始http请求时,Yarp是不起作用的。我能做些什么让它这样工作吗,这样我就可以在Github上应用与我上面链接中的那个家伙相同的修复程序了?然后下一步是将GET http url的后半部分转发到googleapi,我也不确定该怎么做。

    我得到了一个html响应,下面是它的相关部分:

        <a href=//www.google.com/>
        <span id=logo aria-label=Google></span>
    </a>
    <p>
        <b>404.</b>
        <ins>That’s an error.</ins>
    <p>
        The requested URL <code>/maps/api/googlemapswebservice/place/autocomplete/json?input=a &amp;location=-36.8508827%2C174.7644881 &amp;radius=500 &amp;types=establishment &amp;key=xxxxxxxxxxxxxxxxxxxxxxxxxx</code>
        was not found on this server.  <ins>That’s all we know.</ins>
    

    它似乎正在进入谷歌。

    如果我将群集地址更改为:

    “地址”:“https://www.facebook.com/“

    它返回facebook.com的html。

    所以我认为我的查询参数没有任何作用,它将请求发送到集群地址中的确切地址。 我们如何将查询参数获取到集群地址中?

    0 回复  |  直到 1 年前
        1
  •  0
  •   BeniaminoBaggins    1 年前

    我需要使用 Direct Forwarding

    我基本上是从链接中的文档中复制了代码,并进行了一些小的调整。

    在Startup类中,添加一个嵌套的私有类:

    private class CustomTransformer : HttpTransformer
    {
        public override async ValueTask TransformRequestAsync(HttpContext httpContext,
            HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
        {
            // Copy all request headers
            await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
    
            // Customize the query string:
            var queryContext = new QueryTransformContext(httpContext.Request);
    
            // Assign the custom uri. Be careful about extra slashes when concatenating here. RequestUtilities.MakeDestinationAddress is a safe default.
            proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress("https://maps.googleapis.com/maps/api", httpContext.Request.Path, queryContext.QueryString);
    
            // Suppress the original request header, use the one from the destination Uri.
            proxyRequest.Headers.Host = null;
        }
    }
    

    ConfigureServices内部:

    services.AddHttpForwarder();
    

    内部配置:

    var httpClient = new HttpMessageInvoker(new SocketsHttpHandler()
    {
        UseProxy = false,
        AllowAutoRedirect = false,
        AutomaticDecompression = DecompressionMethods.None,
        UseCookies = false,
        ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
        ConnectTimeout = TimeSpan.FromSeconds(15),
    });
    var transformer = new CustomTransformer(); // or HttpTransformer.Default;
    var requestConfig = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    
        RequestDelegate googleMapsApi = async httpContext =>
        {
            var error = await forwarder.SendAsync(httpContext, "https://maps.googleapis.com/maps/api/",
            httpClient, requestConfig, transformer);
            // Check if the operation was successful
            if (error != ForwarderError.None)
            {
                var errorFeature = httpContext.GetForwarderErrorFeature();
                var exception = errorFeature.Exception;
            }
        };
    
        endpoints.Map("/place/{**catch-all}", googleMapsApi);
        endpoints.Map("/geocode/{**catch-all}", googleMapsApi);
    });
    
    推荐文章