【问题标题】:.NET Core API returning response from Web API not including cookies.NET Core API 从 Web API 返回响应,不包括 cookie
【发布时间】:2021-10-29 07:35:52
【问题描述】:

我有一个 .NET Web API 控制器,其中包含以下登录方法:

[HttpPost]
[AllowAnonymous]
[Route("api/account/login")]
//Web API Controller method
public virtual async Task<IHttpActionResult> Login(LoginViewModel model)
{
        SignInStatus response = await this.SignInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, shouldLockout: true);
        if (response == SignInStatus.Success)
            return Ok();

        return BadRequest();
}

该方法返回一个HttpResponseMessage,其中包含许多标头,包括Set-Cookie

我需要做的是从一个用 .NET Core 3.1 编写的控制器调用这个 Web API 控制器并返回 HttpResponseMessage 不变。这是我目前拥有的:

    [HttpPost]
    [Route("[action]")]
    //.NET Core Controller method
    public async Task<ActionResult> Login(LoginViewModel model)
    {
        HttpClient httpClient = new HttpClient();
        HttpResponseMessage response = await httpClient.PostAsync(WebApiControllerURI, new JsonContent(model));
        return Ok(response);
    }

但是,在来自 .NET Core 的响应中,Set-Cookie 不是标头,而是包含在响应正文中:

    {
      "Key": "Set-Cookie",
      "Value": [
        ".AspNet.ApplicationCookie=...."
      ]
    },

当我尝试显式返回 HttpResponseMessage 时得到相同的结果:

    [HttpPost]
    [Route("[action]")]
    public async Task<HttpResponseMessage> Login(LoginViewModel model)
    {
        HttpClient httpClient = new HttpClient();
        HttpResponseMessage response = await httpClient.PostAsync(serverUrl + LoginUri, new JsonContent(model));
        return response;
    }

如何通过 .NET Core 控制器从 Web API 控制器返回响应并保留 Headers 属性中的标头?

【问题讨论】:

  • 您是否尝试直接返回HttpResponseMessage?示例:c-sharpcorner.com/UploadFile/dacca2/…
  • @Serhii 是的,我做到了。我更新了我的问题,表明我尝试明确返回 HttpResponseMessage
  • HttpClient 是什么?它是您构建的吗?你能给我们看一下代码吗?当 HTTPClient 收到它们时,您可以将这些 Header 添加到 HttpResponseMessage
  • @Alen.Toma 这是我正在使用的 System.Net.Http.HttpClient 类。
  • 另外,您可以尝试创建自定义 IActionResult:stackoverflow.com/a/54137811/8978576

标签: c# http asp.net-web-api


【解决方案1】:

当您使用return Ok(response) 或仅使用return response 时,框架将获取HttpResponse 对象并将其序列化为json。

要代理响应,请查看此堆栈溢出问题Creating a proxy to another web api with Asp.net core

代码是这样的:

/* Copied from the linked stack overflow answer.  Only part of the code since the linked question was about a full proxy. */
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage responseMessage)
        {
            if (responseMessage == null)
            {
                throw new ArgumentNullException(nameof(responseMessage));
            }

            var response = context.Response;

            response.StatusCode = (int)responseMessage.StatusCode;
            foreach (var header in responseMessage.Headers)
            {
                response.Headers[header.Key] = header.Value.ToArray();
            }

            foreach (var header in responseMessage.Content.Headers)
            {
                response.Headers[header.Key] = header.Value.ToArray();
            }

            // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
            response.Headers.Remove("transfer-encoding");

            using (var responseStream = await responseMessage.Content.ReadAsStreamAsync())
            {
                await responseStream.CopyToAsync(response.Body, _streamCopyBufferSize, context.RequestAborted);
            }
        }
    [HttpPost]
    [Route("[action]")]
    //.NET Core Controller method
    public async Task<ActionResult> Login(LoginViewModel model)
    {
            HttpResponseMessage response = await httpClient.PostAsync(WebApiControllerURI, new JsonContent(model));
            await HttpContext.CopyProxyHttpResponse(response);
            return Ok();
    }

另一种选择是像 AspNetCore.Proxy 这样的库,具体取决于您需要代理多少。

【讨论】:

  • 谢谢。我会看看 AspNetCore.Proxy 是否符合要求。
  • 你从哪里得到_streamCopyBufferSize
  • @DavidBrower 不确定,这是直接从引用的堆栈答案中复制的。
【解决方案2】:

如果你想在你的 API 请求中添加一个 cookie,那么有两种方法:

方法一:启动时

与静态 cookie 一起使用。

// Method 1 - In Startup
app.Use(async (context, next) =>
{
    var cookieOptions = new CookieOptions()
    {
        Path = "/",
        Expires = DateTimeOffset.UtcNow.AddHours(1),
        IsEssential = true,
        HttpOnly = false,
        Secure = false,
    };
    context.Response.Cookies.Append("MyCookie", "TheValue", cookieOptions);

    await next();
});

方法2:在API中

当你有一个改变值的 cookie 时使用:

[HttpPost("TestCookie")]
public async Task TestCookie(string cookieName, string cookieValue)
{
    // Method 2 - Add to current context
    var context = HttpContext;
    var cookieOptions = new CookieOptions()
    {
        Path = "/",
        Expires = DateTimeOffset.UtcNow.AddHours(1),
        IsEssential = true,
        HttpOnly = false,
        Secure = false,
    };

    context.Response.Cookies.Append(cookieName, cookieValue, cookieOptions);
}

始终返回上下文,即使您没有返回语句。因此,您只需在上下文中设置 cookie 标头,它就会自动返回。

【讨论】:

    猜你喜欢
    • 2018-10-03
    • 2020-06-04
    • 2016-10-16
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 2020-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多