如何通过POST方法将参数传递给Azure函数?

60

我正在尝试编写一个简单的Azure函数以了解它。将有3个函数:

  • 1个函数用于向数据库表中插入一行。该表将包含由用户键入并通过GET传递的当前日期和字符串参数。
  • 1个与前面类似的函数,但通过POST传递参数。
  • 1个函数用于读取表格并显示其内容。

我已经能够完成第一个和第三个功能。但是我无法通过POST传递参数。我搜索了示例,但无法成功运行它们。客户端应用程序是Windows Forms应用程序。

有人能否给我展示一个如何通过POST传递参数到函数并如何读取它们的示例?

提前感谢

编辑:

这是通过GET传递参数的代码(这很好用):

private void button2_Click(object sender, EventArgs e)
{
    string cadena = lsql1.Text + "?notas=" + tNotas.Text;

    try
    {
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(cadena);
        HttpWebResponse res = (HttpWebResponse)req.GetResponse();

        if (res.StatusCode == HttpStatusCode.OK)
        {
            MessageBox.Show("Grabado");
        }
        else
        {
            MessageBox.Show(res.StatusDescription);
        }
    }catch (WebException ex)
    {
        using (Stream s = ex.Response.GetResponseStream())
        {
            StreamReader sr = new StreamReader(s);
            string text = sr.ReadToEnd();
            text = text.Substring(1, text.Length - 2);
            sr.Close();
            text = text.Replace("\\", "");
            text = "{" + text + "}";
            Error mensajeError = JsonConvert.DeserializeObject<Error>(text);

            MessageBox.Show(mensajeError.ExceptionMessage);
        }

    }
}

以下是接收并插入数据的代码(已经可用):

[FunctionName("sql1")]
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    try
    {
        log.Info("C# HTTP trigger function processed a request.");

        var cnnString = "Server=SERVIDOR;Database=base_prueba;User ID =azure;Password=0000;Trusted_Connection=False;Encrypt=False;";

        using (SqlConnection connection = new SqlConnection(cnnString))
        {
            connection.Open();
            SqlCommand cmd = connection.CreateCommand();

            DateTime fecha = DateTime.Today;

            string notas = req.GetQueryNameValuePairs()
            .FirstOrDefault(q => string.Compare(q.Key, "notas", true) == 0)
            .Value;

            // insert a log to the database
            cmd.CommandText = "INSERT INTO Prueba_Azure (fecha, notas) VALUES ('" + fecha.ToString() + "', '" + notas + "')";
            cmd.ExecuteNonQuery();
        }

        // Get request body
        dynamic data = await req.Content.ReadAsAsync<object>();

        return name == req.CreateResponse(HttpStatusCode.OK, "Done");
    }
    catch (Exception ex)
    {
        HttpResponseMessage res = req.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
        return res;
    }
}

我想要的是通过POST方法来实现这个目标


请发布你目前的函数示例。你是用什么语言编写它们的?你可以使用 Node.js 的 JavaScript 编写 Azure 函数,还可以使用 ASP.NET 的 C#:https://visualstudiomagazine.com/articles/2017/04/01/implementing-webhooks-azure-functions.aspx - Dai
抱歉,我正在使用C#编写应用程序。我已经添加了我所编写的代码。 - davidrgh
curl怎么样?请参见https://dev59.com/xWMl5IYBdhLWcg3wMUeP - Winter Singha
谷歌把我带到了这里。我知道这是一个测试项目,但值得一提的是,微软建议不要以明文形式公开连接字符串:“作为最佳安全实践,在函数应用程序设置中存储连接字符串和其他机密信息。”此外,我也不会返回异常消息,因为它们是在服务器端生成的;这可能会向公众暴露一些您想保持私密的信息:您应该在服务器端记录日志,以便可以“过滤”错误响应以包含更少的详细信息 - 例如,对于最常见的错误返回自定义错误代码。 - Ama
13个回答

93

如果你是通过 Google 来到这里的,以下是2019年3月的实现方式(使用 Azure Functions v3):


public static async void Run(
            [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
            HttpRequest req,
            ILogger log)
        {
            var content = await new StreamReader(req.Body).ReadToEndAsync();

            MyClass myClass = JsonConvert.DeserializeObject<MyClass>(content);
            
        }

现在(2020年12月),使用HTTP触发器创建新函数时,脚手架将为您提供完整的代码。谢谢。 - Shockwaver
我们可以在这里删除 StreamReader 并只使用一行代码,使用 System.Text.JsonMyClass myClass = await JsonSerializer.DeserializeAsync<MyClass>(req.Body); - shehanpathi

45

要从请求体(post请求)中获取请求内容,您可以使用req.Content.ReadAsAsync方法。以下是代码示例。

示例请求体。

{
    "name": "Azure"
}

定义一个类来反序列化提交的数据。

public class PostData
{
    public string name { get;set; }    
}

获取提交的数据并显示。

PostData data = await req.Content.ReadAsAsync<PostData>();
log.Info("name:" + data.name);

客户端代码,用于发送 POST 请求。

HttpWebRequest req = (HttpWebRequest)WebRequest.Create("function-url");
req.Method = "POST";
req.ContentType = "application/json";
Stream stream = req.GetRequestStream();
string json = "{\"name\": \"Azure\" }";
byte[] buffer = Encoding.UTF8.GetBytes(json);
stream.Write(buffer,0, buffer.Length);
HttpWebResponse res = (HttpWebResponse)req.GetResponse();

1
参数是HttpRequest而不是HttpRequestMessage,所以您需要查看下一个答案。 - D-Go
1
在NET5中:var legs = await req.ReadFromJsonAsync<PostData>(); - Sith2021

12

如果您正在使用 System.Text.Json,您可以通过一行代码读取POST数据:

public static async Task Run(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
    HttpRequest req,
    ILogger log)
{
    MyClass myClass = await JsonSerializer.DeserializeAsync<MyClass>(req.Body);
}

如果你正在使用Newtonsoft.Json,请查看Allen Zhang的答案


7

如果要将参数作为POST请求传递,需要执行以下操作:

  1. Make Json model of the parameters that u need to pass,ex:

    {"UserProfile":{ "UserId":"xyz1","FirstName":"Tom","LastName":"Hank" }}
    
  2. Post your data model using client like POSTMAN

    enter image description here

  3. Now you will get the posted content in HttpRequestMessage body, sample code is as follows:

    [FunctionName("TestPost")]
    public static HttpResponseMessage POST([HttpTrigger(AuthorizationLevel.Function, "put", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
    {
        try
        {
            //create redis connection and database
            var RedisConnection = RedisConnectionFactory.GetConnection();
            var serializer = new NewtonsoftSerializer();
            var cacheClient = new StackExchangeRedisCacheClient(RedisConnection, serializer);
    
            //read json object from request body
            var content = req.Content;
            string JsonContent = content.ReadAsStringAsync().Result;
    
            var expirytime = DateTime.Now.AddHours(Convert.ToInt16(ConfigurationSettings.AppSettings["ExpiresAt"]));
    
            SessionModel ObjModel = JsonConvert.DeserializeObject<SessionModel>(JsonContent);
            bool added = cacheClient.Add("RedisKey", ObjModel, expirytime); //store to cache 
    
            return req.CreateResponse(HttpStatusCode.OK, "RedisKey");
        }
        catch (Exception ex)
        {
            return req.CreateErrorResponse(HttpStatusCode.InternalServerError, "an error has occured");
        }
    }
    

5
你可以将你的自定义数据类作为参数提供给 HttpTrigger 参数。这样,你就不必亲自去处理 JSON 反序列化了。
public async Task<IActionResult> UpdateAccount(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "api/v1/accounts/{id:guid}")] 
        SomeData someData,  // <----- Post body ends up here automatically
        HttpRequest req,
        Guid id,
        ILogger log)
{
    log.LogInformation ("Got POST with " + someData.Foo);
}


public class SomeData
{
    public string Foo { get; set; } = null!;
}

1
我发现如果我将Foo作为int传递,它会被转换成字符串并且没有问题。但是如果我添加int Moo并将其作为字符串发送,则会出现500代码错误。因此到目前为止,我可能会建议不要“搞乱”JSON反序列化? - Chef Gladiator

3
我们可以使用System.Text.Json来仅用一行代码完成它。
public static async void Run(
        [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]
        HttpRequest req,
        ILogger log)
    {
        MyClass myClass = await JsonSerializer.DeserializeAsync<MyClass>(req.Body);
        
    }

2
查询字符串(名称/值对)默认情况下会作为POST请求的HTTP消息正文发送,而不是作为查询字符串发送。GetQueryNameValuePairs方法将解析查询字符串,并默认情况下无法与POST请求一起使用。
对于POST请求,您可以使用类似以下的内容:
var content = request.Content;
string contentInString = content.ReadAsStringAsync().Result;

3
请注意,此代码不适用于生产环境(异步死锁)。 - Verbe

1
以下是使用自定义类完成的方法:

自定义类

Azure Function

[FunctionName("PostParameterFunction")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequestMessage req, ILogger log)
   {
      log.LogInformation("C# HTTP trigger function processed a request.");

       try
        {
             // Convert all request perameter into Json object

                var content = req.Content;
                string jsonContent = content.ReadAsStringAsync().Result;
                dynamic requestPram = JsonConvert.DeserializeObject<RequestModel>(jsonContent);

                // Validate the required param

                if (string.IsNullOrEmpty(requestPram.FirstName))
                {
                    return req.CreateResponse(HttpStatusCode.OK, "Please enter First Name!");
                }
                if (string.IsNullOrEmpty(requestPram.LastName))
                {
                    return req.CreateResponse(HttpStatusCode.OK, "Please enter Last Name!");
                }


                //Create object for partner Model to bind the response on it

                RequestModel objRequestModel = new RequestModel();

                objRequestModel.FirstName = requestPram.FirstName;
                objRequestModel.LastName = requestPram.LastName;

                //Return Request Model

                return req.CreateResponse(HttpStatusCode.OK, objRequestModel);
         }
        catch (Exception ex)
         {

                return req.CreateResponse(HttpStatusCode.OK, "Cannot Create Request! Reason: {0}", string.Format(ex.Message));
         }

        }

请求类:
 public class RequestModel
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

    }

请求输入:

{
    "FirstName": "Kiron",
    "LastName":"Test"
}

PostMan 输出示例:

enter image description here


1
你需要将数据附加到POST请求的主体中,并正确处理它:
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
    // This reads your post request body into variable "data"
    string data = await req.Content.ReadAsStringAsync();
    // Here you can process json into an object
    dynamic parsed = JsonConvert.DeserializeObject(data);

    return exitstring == null
        ? req.CreateResponse(HttpStatusCode.BadRequest, "Something went wrong, sorry")
        : req.CreateResponse(HttpStatusCode.OK);
}

您可以在此处找到一个略微不同的示例,以及精确的示例此处


0

重点在这里 --> https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=in-process%2Cfunctionsv2&pivots=programming-language-csharp

    [FunctionName("LuckyNumber")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(
        AuthorizationLevel.Function,
        "get", "post",
        Route = "max/{max:int?}/min/{min:int?}")] HttpRequest req,
        int? max, <-- Parameter max
        int? min, <-- Parameter min
        ILogger log)
    {
        int? maxInternal = max;
        int? minInternal = min;
    }

备注:我正在使用 .NET 6


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接