Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Azure Functions v3 HttpTrigger: request body is empty #5405

Open
myarotskaya opened this issue Dec 17, 2019 · 27 comments
Open

Azure Functions v3 HttpTrigger: request body is empty #5405

myarotskaya opened this issue Dec 17, 2019 · 27 comments

Comments

@myarotskaya
Copy link

myarotskaya commented Dec 17, 2019

HttpTrigger works incorrectly in the following conditions:

  • Azure Functions v3
  • TargetFramework: netcoreapp3.1
  • Microsoft.NET.Sdk.Functions version 3.0.2
  • Code:
        [FunctionName("RunNetCore3")]
        public static async Task<string> RunNetCore3Async(
            [HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "netcore3/{id}")]
            CustomRouteParameter parameter,
            HttpRequest request,
            CancellationToken cancellationToken)
        {
            using (var reader = new StreamReader(request.Body, Encoding.UTF8))
            {
                return await reader.ReadToEndAsync();
            }
        }
  • The request body in the request variable is empty if request contains Content-Type: application/json header (works ok with any other Content-Type values except application/json). So in the example the empty response body will be returned which is unexpected.

Investigative information

I've created the repository to demonstrate this issue. The source code of this repository is deployed to the Function App.

  • Timestamp: 09:27 AM (UTC Time)
  • Function App version: 3.0
  • Function App name: NetCore3HttpBindingBug
  • Function name(s) (as appropriate): RunNetCore3
  • Invocation ID: 32894c31-74ac-4a98-8f94-fe6c76662d7d
  • Region: Central US

Repro steps

  • Send POST https://netcore3httpbindingbug.azurewebsites.net/api/netcore3/qqq request with some body and Content-Type: application/json header.

Expected behavior

Request's body is returned in the response.

Actual behavior

Request's body is not returned in the response.

Known workarounds

Do not send Content-Type: application/json header or send any other value in the Content-Type header.

Related information

The same code works correct in Azure Functions v2 on netcoreapp2.1 with Microsoft.NET.Sdk.Functions version 1.0.29 and in ASP.NET Core 3.1 Web Application.

There are two endpoints to check it (see the repository):

  • Send POST /netcore2/some-id request with some body and Content-Type: application/json header
  • Send POST /aspnetcore3/some-id request with some body and Content-Type: application/json header

In both cases the request body will be returned in the response (I didn't deploy it to any Function App but it's reproducible locally as well).

@myarotskaya
Copy link
Author

Another workaround @fabiocav mentioned: set FUNCTIONS_V2_COMPATIBILITY_MODE to true in the App Settings.

@pragnagopa pragnagopa added this to the Triaged milestone Jan 6, 2020
@myarotskaya
Copy link
Author

Hello @pragnagopa, could you please confirm that it's a valid issue and if so, is it planned to be fixed on the Azure Functions side? Is there any ETA?

@andersekenstierna
Copy link

Hi. Working on a customer project and upgraded to version 3.1. I can verify that this is still an issue that needs to be resolved. Setting FUNCTIONS_V2_COMPATIBILITY_MODE to true works as a workaround though.

@pragnagopa
Copy link
Member

Please continue using FUNCTIONS_V2_COMPATIBILITY_MODE. We will update this issue with further details. No ETA yet.

@bstoked
Copy link

bstoked commented Apr 8, 2020

Any word on this? Upgrading to v3 broke our microservices.

@JohnPelaschier
Copy link

Having this issue and setting FUNCTIONS_V2_COMPATIBILITY_MODE does not help for me. Runs fine locally but nothing works when deployed to Azure. Am I missing something?

@TMUNYU
Copy link

TMUNYU commented Jul 31, 2020

FUNCTIONS_V2_COMPATIBILITY_MODE is not doing the trick for me. You guys need to put a GIANT warning on the functions overview about this. I wasted so much time going in circles about this because I was not aware of this known issue. I am sure others have wasted time too. It is good to be more transparent about non obvious bugs like this.

@TMUNYU
Copy link

TMUNYU commented Jul 31, 2020

Found another work around for others. In my case I was using GET on the function. If you use POST instead the body will come in correctly. I am not using the FUNCTIONS_V2_COMPATIBILITY_MODE.

@DanielTongAwesome
Copy link

Problem still exist when I am using:
Azure Functions Core Tools (3.0.2798 Commit hash: d9d99872a51c04b1c2783198b1ee1104da6b064f)

but after I tried it couple times, the issue suddenly disappear ... and get_json() returns json data ... this is really strange

if u are using postman:

  1. in body, header enter content-type: application/json
  2. in body type your json msg
  3. use POST and include a body

image
image

@MateRadz
Copy link

MateRadz commented Sep 8, 2020

Any update on this issue? Setting FUNCTIONS_V2_COMPATIBILITY_MODE to true does not work. What is frustrating is that it works when invoked from the Test/Run form in the portal, but does not work via Postman.

@anthonychu
Copy link
Member

I was able to repro this with @myarotskaya's repo. Looks like the problem has to do with model binding reading the body stream. By the time the function executes, there's nothing left to read. @fabiocav @pragnagopa Is this the desired behavior for v3? Feels like this is a bug if there's no other way to get access to the request body in this scenario.

@bstoked @TMUNYU @DanielTongAwesome @MateRadz Can you confirm that you are all experiencing the same issue? The fact that the compatibility mode doesn't solve it for everyone might indicate a different problem. Please share a repro if possible.

@MateRadz
Copy link

MateRadz commented Sep 8, 2020

I do not knot your internal schedule but for me it is a new issue as my function without any change in code worked for several days until the last ok at 25.08.2020, 13:15:05.009. The next call at 25.08.2020, 19:16:20.619 (UTC) was the first not working an it is like this till today. So for me it may have been related to your internal updates, if there where any. As mentioned when called directly from Test/Run on Azure Portal it works.

@mike1880
Copy link

Found another work around for others. In my case I was using GET on the function. If you use POST instead the body will come in correctly. I am not using the FUNCTIONS_V2_COMPATIBILITY_MODE.

That's not true for me at least; the first time I tripped over this issue it was with a POST message

@mdddev
Copy link

mdddev commented Oct 8, 2020

I stumbled on this while investigating why the request body received from a (deployed to azure) function app is empty. Contrary to the above, I don't see this behaviour running locally. Even with content-type set to application/json I can successfully pass along a non-empty body.

PS C:\Users\me\source\project> func -v
3.0.2931

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <LangVersion>8.0</LangVersion>
    <Nullable>enable</Nullable>
    <AzureFunctionsVersion>v3</AzureFunctionsVersion>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.7" />
  </ItemGroup>
</Project>
namespace my.namespace
{
    public static class Notify
    {
        [FunctionName(nameof(Notify))]
        public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = "notify")] HttpRequest req,
        [Queue("name", Connection = "connName")] IAsyncCollector<string> myDestinationQueue,
        ILogger log)
        {
                using var r = new StreamReader(req.Body, Encoding.UTF8);
                var bodyStr = await r.ReadToEndAsync();
                await myDestinationQueue.AddAsync(bodyStr);
                // do stuff...
                return new OkObjectResult(1);
        }
    }
}

@MateRadz
Copy link

MateRadz commented Oct 8, 2020

I do not knot your internal schedule but for me it is a new issue as my function without any change in code worked for several days until the last ok at 25.08.2020, 13:15:05.009. The next call at 25.08.2020, 19:16:20.619 (UTC) was the first not working an it is like this till today. So for me it may have been related to your internal updates, if there where any. As mentioned when called directly from Test/Run on Azure Portal it works.

The simplest workaround which worked for me was redeployment of function with MS provided example http trigger function.
After that worked I copied my source to the function and after deploying again it started to work.

@prabh-62
Copy link

I tried to reproduce the issue with a new func project however I couldn't

System

  • func --version -> 3.0.2931
  • dotnet --version -> 3.1.402

Steps

  • > func new ImageService --dotnet
  • > cd ImageService
  • > func init (Add a HTTP Trigger)
  • Swap code in the new HTTP Trigger class with this snippet
public static class CreatePDF
    {
        [FunctionName(nameof(CreatePDF))]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "createPDF")]
            HttpRequestMessage req,
            ILogger log)
        {
            var body = await req.Content.ReadAsStringAsync().ConfigureAwait(false);
            log.LogInformation(body);
            return new OkObjectResult(body);
        }
    }

    public static class MergePDF
    {
        [FunctionName(nameof(MergePDF))]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "mergePDF")]
            HttpRequest req,
            ILogger log)
        {
            var reader = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true);
            {
                var body = await reader.ReadToEndAsync().ConfigureAwait(false);
                log.LogInformation(body);
                return new OkObjectResult(body);
            }
        }
    }
  • Now, invoke both the APIs and check for API response. (Both APIs return the request body for me)

request_body_v3

@prabh-62
Copy link

@anthonychu The issue with @myarotskaya's git repo is the order of parameters
myarotskaya_issue

Once, the order of parameters is fixed, the request body comes through
myarotskaya_issue_fixed

@prabh-62
Copy link

Created #6780

@mike1880
Copy link

I tried to reproduce the issue with a new func project however I couldn't

I can confirm this is now working for me with Microsoft.NET.Sdk.Functions 3.0.9, both in local emulator and in Azure itself, and with Get as well as Post.

@siamaksh1367
Copy link

siamaksh1367 commented Jan 22, 2021

Use Https instead of http
with the default setup of an http trigger azure function , that worked for me

@KenticoDevTrev
Copy link

Ultimately i had to switch to POST and use in function Model Binding, and NOT rely on parsing the request body. It seems no matter how hard I try, the body is often empty when the azure function is 'waking up' (first hit on a cold function), but on subsequent hits it is valid and works.

FUNCTIONS_V2_COMPATIBILITY_MODE to true didn't do me any good.

This is my new start:

[FunctionName("GetComics")]
        [FixedDelayRetry(5, "00:00:02")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]
            GetComicsRequest Request,
            ILogger log
            )
        {
        ...
        var Response = new ComicResponse()
                {
                    Date = (Comics.Count > 0 ? Comics[0].Date : Request.Date != DateTimeHelper.ZERO_TIME ? Request.Date : DateTime.Now),
                    Comics = Comics
                };
                return new JsonResult(Response);
        }

@cbailiss
Copy link

cbailiss commented Jul 7, 2023

I have also been suffering with the issue of an empty body with a runtime v4 app based on C# .NET 6 LTS.

I have a working set of code that has run fine in production for years (earlier version of the runtime). After moving it to .NET 6 LTS and runtime v4, the following code at the start of the function definition was not returning the request body:

                string sRequestBody = null;
                if (oRequest.Body != null)
                {
                    using (StreamReader oReader = new StreamReader(oRequest.Body))
                    {
                        sRequestBody = await oReader.ReadToEndAsync();
                    }
                }

The function was originally declared as:

        [FunctionName("TestPost")]
        public static async Task<IActionResult> TestPost(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = TrainDataHttpRoutes.Test)]
            ExecutionContext context, HttpRequest oRequest, ILogger oLog)

What fixed it was removing the ExecutionContext parameter:

        [FunctionName("TestPost")]
        public static async Task<IActionResult> TestPost(
            [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = TrainDataHttpRoutes.Test)]
            HttpRequest oRequest, ILogger oLog)

Just posting here in case helps others as this caused me a lot of frustration to figure out.

@cbailiss
Copy link

I have now suffered a recurrence of this issue. The above Azure Function has been running fine for the last 3 weeks has now suddenly stopped working with the issue again being an empty body. I've made no changes/done no deployments since 3 weeks ago. What was working yesterday has suddenly stopped working today with no change/intervention from me. The exact same test case (same request) that worked a week ago is not working today. This bug in Azure Functions is very frustrating.

@bsmithQSC
Copy link

Can anyone confirm if this has been resolved yet? On v4 and having the same issue.

@tslavik
Copy link

tslavik commented Dec 20, 2023

Can anyone confirm if this has been resolved yet? On v4 and having the same issue.

I do not know your language, but in typescript this is working for me:
await request.json() where request is HttpRequest class.

@fabiocav fabiocav removed this from the Triaged milestone Jan 23, 2024
@dalee-bis
Copy link

dalee-bis commented Jan 29, 2024

For others running into this issue, I found that switching to HttpRequestData allowed me to access the request body without needing to change any other code.

Perhaps related to this note in the payload section documentation on .NET Isolated?

Type Description
HttpRequest Use of this type requires that the app is configured with ASP.NET Core integration in .NET Isolated.
This gives you full access to the request object and overall HttpContext.
HttpRequestData A projection of the request object.

@Garran-Workspace
Copy link

Good day,
I am getting an intermittent empty body from C# .NET 8 Http trigger Azure Function

I have also posted the issue on stackoverflow.

I am encountering an intermittent issue when calling a POST method hosted on Azure Functions using C# .NET 8 dotnet-isolated http trigger. The request body appears to be empty approximately 40% to 60% of the time without async and with async it is around 10%, and I am uncertain about the cause.

I have developed a basic function to serve as a mock API. Its sole purpose is to return an HTTP status code and a JSON object. In all cases, when I call the function, I receive a 200 response. However, in some cases, the response does not include a body.

Here is a code example with async:

[Function("TokenOk")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "TokenOk")] HttpRequest req)
{
    _logger.LogInformation($"Executing TokenOk function.");

    var json = new
    {
        AccessToken = "eyJhbGciOiJSUzI1....",
        ExpiryInSeconds = 3600,
        IssuedAtUTC = "2024-03-25T13:42:14.6599966Z"
    };
    
    // When I increase the delay to 100, to 1000, the empty body ratio gets less
    await Task.Delay(10);

    return new OkObjectResult(json);
}

Here is a code example without async:

[Function("TokenOk")]
public IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "TokenOk")] HttpRequest req)
{
    _logger.LogInformation($"Executing TokenOk function.");

    var json = new
    {
        AccessToken = "eyJhbGciOiJSUzI1....",
        ExpiryInSeconds = 3600,
        IssuedAtUTC = "2024-03-25T13:42:14.6599966Z"
    };

    return new OkObjectResult(json);
}

To investigate further, I have created a small console application to hit the endpoint multiple times and check for the presence of a response body:

Data in Response 710
Data in Response 711
Data in Response 712
Data in Response 713
Response 714 is empty
Data in Response 715
Response 716 is empty
Data in Response 717
Data in Response 718
Data in Response 719
Data in Response 720
Response 721 is empty
Response 722 is empty
Data in Response 723
Data in Response 724
Data in Response 725
Data in Response 726
Data in Response 727
Data in Response 728
Data in Response 729
Data in Response 730
Data in Response 731

Here is an example of the environment variables used in the Azure Function:

[
  {
    "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
    "value": "InstrumentationKey=...",
    "slotSetting": false
  },
  {
    "name": "AzureWebJobsStorage",
    "value": "DefaultEndpointsProtocol=http..",
    "slotSetting": false
  },
  {
    "name": "FUNCTIONS_EXTENSION_VERSION",
    "value": "~4",
    "slotSetting": false
  },
  {
    "name": "FUNCTIONS_WORKER_RUNTIME",
    "value": "dotnet-isolated",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_ENABLE_SYNC_UPDATE_SITE",
    "value": "true",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_RUN_FROM_PACKAGE",
    "value": "1",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_USE_PLACEHOLDER_DOTNETISOLATED",
    "value": "1",
    "slotSetting": false
  },
  {
    "name": "WEBSITES_ENABLE_APP_SERVICE_STORAGE",
    "value": "true",
    "slotSetting": false
  }
]

I tried switching IActionResult with HttpResponseData, but that didn't help. I attempted changing HttpResponseData to async. I even deleted the Azure Function and recreated it, but no luck. I also tried recreating the function locally and then deploying it. This issue only occurs once it's deployed to Azure; it works perfectly locally. I have let the console app that calls the post method run for 1000 times and I still get some with an empty body.

Thank you in advance.

# for free to join this conversation on GitHub. Already have an account? # to comment
Projects
None yet
Development

No branches or pull requests