.NET Core API 从 Web API 返回响应,不包括 cookie

Posted

技术标签:

【中文标题】.NET Core API 从 Web API 返回响应,不包括 cookie【英文标题】:.NET Core API returning response from Web API not including cookies 【发布时间】: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:***.com/a/54137811/8978576 【参考方案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 标头,它就会自动返回。

【讨论】:

以上是关于.NET Core API 从 Web API 返回响应,不包括 cookie的主要内容,如果未能解决你的问题,请参考以下文章

从 .NET Core Web API 调用 SalesForce API 并将响应反序列化为 c# 对象?

从 .NET Core Web API 返回错误消息

从 .NET Core 调用 Web API 到 .NET Framework

如何从 ASP.NET MVC 到 ASP.NET Core Web API 的 PUT?

从 ASP.NET Web API ASP.NET Core 2 返回 HTML 并获取 http 状态 406

为啥从 ASP.NET Core Web API 的 ControllerBase 与 Controller 派生?