[英]Why is my header data missing from my Azure Function Http Trigger in .Net 5 when calling from HttpClient.GetAsync
I have a client using HttpClient.GetAsync to call into a Azure Function Http Trigger in.Net 5.我有一个客户端使用 HttpClient.GetAsync 调用 Azure Function Http 触发器 in.Net 5。
When I call the function using PostMan, I get my custom header data.当我使用 PostMan 调用 function 时,我得到了我的自定义 header 数据。
However, when I try to access my response object (HttpResponseMessage) that is returned from HttpClient.GetAsync, my header data empty.但是,当我尝试访问从 HttpClient.GetAsync 返回的响应 object (HttpResponseMessage) 时,我的 header 数据为空。
I have my Content data and my Status Code.我有我的内容数据和我的状态代码。 But my custom header data are missing.
但是我自定义的header数据不见了。
Any insight would be appreciated since I have looking at this for hours.任何见解都将不胜感激,因为我已经看了好几个小时了。
Thanks for you help.谢谢你的帮助。
Edit: Here is the code where I am making the http call:编辑:这是我拨打 http 电话的代码:
public async Task<HttpResponseMessage> GetQuotesAsync(int? pageNo, int? pageSize, string searchText)
{
var requestUri = $"{RequestUri.Quotes}?pageNo={pageNo}&pageSize={pageSize}&searchText={searchText}";
return await _httpClient.GetAsync(requestUri);
}
Edit 8/8/2021: See my comment below.编辑 8/8/2021:请参阅下面的评论。 The issue has something to do with using Blazor Wasm Client.
该问题与使用 Blazor Wasm 客户端有关。
For anyone having problems after following the tips on this page, go back and check the configuration in the host.json file.对于按照本页提示操作后遇到问题的任何人,请返回 go 并检查 host.json 文件中的配置。 you need the Access-Control-Expose-Headers set to * or they won't be send even if you add them.
您需要将 Access-Control-Expose-Headers 设置为 *,否则即使您添加它们也不会发送。 Note: I added the "extensions" node below and removed my logging settings for clarity.
注意:为了清楚起见,我在下面添加了“扩展”节点并删除了我的日志记录设置。
host.json (sample file): host.json(示例文件):
{
"version": "2.0",
"extensions": {
"http": {
"customHeaders": {
"Access-Control-Expose-Headers": "*"
}
}
}
}
This is because HttpResponseMessage 's Headers
property data type is HttpResponseHeaders but HttpResponseData 's Headers
property data type is HttpHeadersCollection .这是因为HttpResponseMessage的
Headers
属性数据类型是HttpResponseHeaders而HttpResponseData的Headers
属性数据类型是HttpHeadersCollection 。 Since, they are different, HttpResponseHeaders
could not bind to HttpHeadersCollection
while calling HttpClient.GetAsync
(as it returns HttpResponseMessage ).由于它们不同,因此
HttpResponseHeaders
在调用HttpClient.GetAsync
时无法绑定到HttpHeadersCollection
(因为它返回HttpResponseMessage )。
I could not find a way to read HttpHeadersCollection through HttpClient
.我找不到通过
HttpClient
读取HttpHeadersCollection的方法。
As long as your Azure function code is emitting the header value, you should be able to read that in your client code from the Headers
collection of HttpResponseMessage
.只要您的 Azure function 代码发出 header 值,您就应该能够在客户端代码中从
HttpResponseMessage
的Headers
集合中读取该值。 Nothing in your azure function ( which is your remote endpoint you are calling ) makes it any different.您的 azure function(这是您正在呼叫的远程端点)中没有任何不同之处。 Remember, your client code has no idea how your remote endpoint is implemented.
请记住,您的客户端代码不知道您的远程端点是如何实现的。 Today it is azure functions, tomorrow it may be a full blown as.net core web api or a REST endpoint written in Node.js. Your client code does not care.
今天它是 azure 功能,明天它可能是一个完整的 as.net 核心 web api 或 Node.js 中编写的 REST 端点。您的客户端代码不关心。 All it cares is whether the Http response it received has your expected header.
它只关心它收到的 Http 响应是否有您预期的 header。
Asumming you have an azure function like this where you are adding a header called total-count
to the response.假设您有一个像这样的 azure function,您要在响应中添加一个名为
total-count
的 header。
[Function("quotes")]
public static async Task<HttpResponseData> RunAsync(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("Quotes");
logger.LogInformation("C# HTTP trigger function processed a request for Quotes.");
var quotes = new List<Quote>
{
new Quote { Text = "Hello", ViewCount = 100},
new Quote { Text = "Azure Functions", ViewCount = 200}
};
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("total-count", quotes.Count.ToString());
await response.WriteAsJsonAsync(quotes);
return response;
}
Your existing client code should work as long as you read the Headers
property.只要您阅读
Headers
属性,您现有的客户端代码就应该可以工作。
public static async Task<HttpResponseMessage> GetQuotesAsync()
{
var requestUri = "https://shkr-playground.azurewebsites.net/api/quotes";
return await _httpClient.GetAsync(requestUri);
}
Now your GetQuotesAsync
method can be called somewhere else where you will use the return value of it (HttpResponseMessage instance) and read the headers.现在可以在其他地方调用您的
GetQuotesAsync
方法,您将在其他地方使用它的返回值(HttpResponseMessage 实例)并读取标头。 In the below example, I am reading that value and adding to a string variable.在下面的示例中,我正在读取该值并将其添加到字符串变量中。 HttpResponseMessage implements IDisposable.
HttpResponseMessage 实现 IDisposable。 So I am using a
using
construct to implicitly call the Dispose
method.所以我使用
using
构造来隐式调用Dispose
方法。
var msg = "Total count from response headers:";
using (var httpResponseMsg = await GetQuotesAsync())
{
if (httpResponseMsg.Headers.TryGetValues("total-count", out var values))
{
msg += values.FirstOrDefault();
}
}
// TODO: use "msg" variable as needed.
The types which Azure function uses for dealing with response headers is more of an implementation concern of azure functions. Azure function 用于处理响应标头的类型更多是 azure 函数的实现关注点。 It has no impact on your client code where you are using HttpClient and HttpResponseMessage.
它对您使用 HttpClient 和 HttpResponseMessage 的客户端代码没有影响。 Your client code is simply dealing with standard http call response (response headers and body)
您的客户端代码只是处理标准的 http 呼叫响应(响应标头和正文)
The issue is not with Blazor WASM, rather if that header has been exposed on your API Side.问题不在于 Blazor WASM,而是 header 是否已暴露在您的 API 端。 In your azure function, add the following -
在您的 azure function 中,添加以下内容 -
Note: Postman will still show the headers even if you don't expose the headers like below.注意: Postman 仍然会显示标题,即使您没有像下面那样公开标题。 That's because, Postman doesn't care about CORS headers.
那是因为 Postman 不关心 CORS 标头。 CORS is just a browser concept and not a strong security mechanism.
CORS 只是一个浏览器概念,并不是一个强大的安全机制。 It allows you to restrict which other web apps may use your backend resources and that's all.
它允许您限制哪些其他 web 应用程序可以使用您的后端资源,仅此而已。
First create a Startup File to inject the HttpContextAccessor首先创建一个启动文件来注入HttpContextAccessor
Package Required: Microsoft.Azure.Functions.Extensions Package 必需:Microsoft.Azure.Functions.Extensions
[assembly: FunctionsStartup(typeof(FuncAppName.Startup))]
namespace FuncAppName
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddScoped<HttpContextAccessor>();
}
}
}
Next, inject it into your main Function -接下来,将其注入您的主 Function -
using Microsoft.AspNetCore.Http;
namespace FuncAppName
{
public class SomeFunction
{
private readonly HttpContext _httpContext;
public SomeFunction(HttpContextAccessor contextAccessor)
{
_httpContext = contextAccessor.HttpContext;
}
[FunctionName("SomeFunc")]
public override Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, new[] { "post" }, Route = "run")] HttpRequest req)
{
var response = "Some Response"
_httpContext.Response.Headers.Add("my-custom-header", "some-custom-value");
_httpContext.Response.Headers.Add("my-other-header", "some-other-value");
_httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "my-custom-header, my-other-header");
return new OkObjectResult(response)
}
If you want to allow all headers you can use wildcard (I think, not tested) -如果您想允许所有标头,您可以使用通配符(我认为,未经测试)-
_httpContext.Response.Headers.Add("Access-Control-Expose-Headers", "*");
You still need to add your web-app url to the azure platform CORS. You can add * wildcard, more info here - https://iotespresso.com/allowing-all-cross-origin-requests-azure-functions/您仍然需要将您的网络应用程序 url 添加到 azure 平台 CORS。您可以在此处添加 * 通配符,更多信息 - https://iotespresso.com/allowing-all-cross-origin-requests-azure-functions/
to enable CORS for Local Apps during development - https://stackoverflow.com/a/60109518/9276081在开发期间为本地应用启用 CORS - https://stackoverflow.com/a/60109518/9276081
Now to access those headers in your Blazor WASM, as an eg you can -现在访问您的 Blazor WASM 中的这些标头,例如您可以 -
protected override async Task OnInitializedAsync()
{
var content = JsonContent.Create(new { query = "" });
using (var client = new HttpClient())
{
var result = await client.PostAsync("https://func-app-name.azurewebsites.net/api/run", content);
var headers = result.Headers.ToList();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.