用Azure函数构建一个二维码生成器的教程

163 阅读16分钟

用Azure函数建立一个二维码生成器

如何建立一个有趣的二维码项目并了解Azure Functions

如果你想学习如何构建Azure Functions,这里有一个有趣的项目。这个项目将是一个有点傻的,但却很有教育意义。

我们将建立一个二维码生成器,100%在Azure函数中运行。互联网上有成千上万的二维码生成器,所以这是一个愚蠢的练习,但我想挑战Azure函数的极限,向你展示它们有多酷,并激励你用它们构建很酷的东西。

在本教程中,你将了解到:

  • Azure函数如何工作以及它们有多简单
  • 如何用.NET库生成QR码
  • 构建这样的东西所需的努力有多少

这很有趣,我希望你能跟上。我们在本教程中要做什么?

  • 创建一个Azure函数
  • 实现一个QR生成器
  • 为它建立一个粗略的前端
  • 用Azure Functions核心工具将其部署到Azure。

在本教程结束时,你将拥有一个实用的二维码生成器,它可能会激励你用Azure函数构建更多很酷的东西。它们结构紧凑、简单,而且容易构建。

你可以在这里找到这个项目的完整源代码

什么是Azure函数?

Azure函数是在Azure中运行的无服务器应用程序。它们是一些小的代码片段,你可以在没有服务器或复杂实例的情况下执行。大多数Azure函数是 "微服务",只做一个小任务,而且做得很好。

Azure函数还可以响应HTTP触发器,充当一种 "小型API"。它们对HTTP请求的响应就像Web API一样,但对函数的设置要少得多。

我开始听起来像个广告,但这是很了不起的。几年前,这个同样的项目需要你建立一个服务器,或者在某个IIS服务器上建立一个ASP.NET Web API。现在,我们只需几行代码就可以做到,并把它推到云端。Azure函数让你可以专注于构建很酷的东西,而不是所有的设置。

要求

以下是本教程中你需要的东西。我将在Windows 11中构建它,但我们不使用Visual Studio。我将使用dotnet驱动,所以如果你愿意,你可以在Mac或OSX上复制它。你必须在你的机器上安装这个(免费)软件。

你将需要:

那么让我们开始吧!

创建一个新的项目

我们将使用Azure CLI为我们创建一个新的Azure函数,我们将使用dotnet驱动来安装软件。

Visual Studio可以为我们自动完成这些工作,但这样做可以更好地了解所涉及的步骤,并且可以在许多平台上完成。

首先,我们将初始化一个新的函数。我们将使用func 命令来创建一个名为QRCodeGen的新项目。我们将指定工作者的运行时间为 "dotnet",以选择C#作为使用的语言。

在你的项目或资源库文件夹中运行这个命令:

Shell

func init QRCodeGen --worker-runtime dotnet

如果你看一下这个文件夹,这里并没有什么: 我们仍然需要在项目中创建一个Azure函数。Azure函数有一套模板,这取决于你要做什么类型的应用。我们要创建一个HTTP触发器,一个响应HTTP请求的函数。

func new --template "Http Trigger" --name QRCodeGen --authlevel anonymous

如果你使用的是Visual Studio Code,你可能会看到这个消息: 选择 "是 "来安装扩展程序。

现在你会看到一个样本函数,func 为你创建的。 如果你想试试,你可以在本地运行它。键入

Shell

func start

然后你会看到函数启动,控制台会给你一些关于如何使用该应用程序的指导:

正如我们所看到的,我们可以向http://localhost:7071/api/QRCodeGen 发送一个GETPOST。让我们在浏览器中加载它,看看一个简单的GET会返回什么。 我们有一个信息显示:

This HTTP triggered function was executed successfully. Pass a name in the query string or in the request body for a personalized response.

好的,很好。让我们深入研究代码,看看这条消息是什么意思。

C#

string responseMessage = string.IsNullOrEmpty(name)
    ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
    : $"Hello, {name}. This HTTP triggered function executed successfully.";

正如你在上面的代码中所看到的,它正在对name 中的一个值进行检查。如果该变量是空的或空的,它将显示我们刚才看到的信息。

但我们如何填充这个值呢?在上面几行,我们看到查询中的一个参数,我们可以使用:

C#

string name = req.Query["name"];

如果它被填充了,它将显示一条包含名称的消息。我们需要向它发送一个URL,并将name 作为一个参数,就像这样:

http://localhost:7071/api/QRCodeGen?name=Jeremy

所以让我们来试试。 这就是我的信息。所以现在我们知道这个函数是按预期工作的。我们加载一个URL,获得参数并修改输出。

为了简单起见,我们将把这个模型用于我们的QR码发生器。我们将建立我们的URL来监听请求,并在一个GET命令中传递值,然后返回一个QR码。让我们开始生成该QR码。

安装QRCode生成工具

将文本变成一个QR码是相对复杂的。幸运的是,你使用的是.NET。你就不必手工建立你的生成器了。这个问题在很久以前就已经解决了。我们将使用一个库来为我们生成一个.PNG的QR码。我们只需要围绕它写一些代码,建立一个工具来解决我们的问题。

首先,让我们安装Manuel BL的QRCode Generator软件包。我们将使用dotnet驱动来完成。我将指定在写这篇文章时的最新版本。

外壳

dotnet add package Net.Codecrete.QrCodeGenerator --version 2.0.1

QRCode生成器很好用,但只能生成.svgs。由于我们想要一个.PNG(位图)格式,并且希望它能在多种环境下工作,我们需要安装SkiaSharp包

外壳

dotnet add package SkiaSharp

SkiaSharp包括生成位图的功能。但你必须下载并将这个文件添加到你的项目中:

github.com/manuelbl/Qr…

在你的项目文件夹中创建一个名为QrCodeBitmapExtensions.cs的文件,并将这个文件的内容复制到其中。这将使你能够处理位图,特别是.PNG文件。

现在我们有了我们的QR码生成器工具,所以让我们让它在我们的函数中工作。

创建QR码生成器功能

如果你打开QRCodeGen.cs ,你会看到为我们生成的Azure Function(一个方法)。它看起来会是这样的:

C#

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

            string name = req.Query["name"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            name = name ?? data?.name;

            string responseMessage = string.IsNullOrEmpty(name)
                ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
                : $"Hello, {name}. This HTTP triggered function executed successfully.";

            return new OkObjectResult(responseMessage);
        }

让我们删除这个方法。在QRCodeGen.cs ,你唯一应该看到的是这个:

C#

namespace QRCodeGen
{
    public static class QRCodeGen
    {

    }
}

接下来,让我们添加一个新方法来生成QR码。

首先,在名称装饰器中添加。这将给这个方法一个名字,并改变访问它的URL:

C#

[FunctionName("GenerateQRCode")]

现在,当我们运行我们的应用程序时,URL将是:

http://localhost:7071/api/GenerateQRCode

这将是我们为生成二维码而调用的URL,我们将从JavaScript中调用它:

接下来,创建该方法:

C#

public static async Task<IActionResult> Generate(
  [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
  {

  }

我们正在创建一个名为Generate的方法。我们将传入一些参数,告诉应用程序我们想要一个HttpTrigger:

[HttpTrigger

而在这个触发器中,我们要传递一些参数。

我们想把我们的授权设置为匿名,这样任何人都可以访问它:

AuthorizationLevel.Anonymous

我们只想接受对这个URL的GET 请求,所以下面的参数指定了这一点:

"get",

然后我们将我们的路由设置为null。如果我们想要一个不同的URL或特定的路由,我们可以在这里指定它。为了简单起见,我们将保持原样:

Route = null)]

接下来,我们将传入一个HttpRequest对象。这将包含来自传入请求的数据,这样我们就可以从中获取参数。当一个GET请求被发送到我们的函数时,我们可以提取诸如头信息、参数等东西:

HttpRequest req

最后,我们将传入一个记录器,这样我们就可以记录信息:

ILogger log

很好,现在我们已经构建了一个方法。让我们把它填满。

从查询字符串中收集信息

用户必须发送他们想变成QR码的文本。这通常是一个URL。我们在早期就决定保持简单的事情。我们将只是从发送到API的查询字符串中收集这些信息。

还记得我们传入方法的HttpRequest吗?我们可以从那里得到我们的查询参数。我们可以建立一个字符串变量,然后从查询字符串中获取参数:

C#

string qrtext = req.Query["qrtext"];

添加以下信息来记录我们的输出。我们要显示发送到我们的qrtext 变量的内容。

C#

log.LogInformation("Generating QR Code for {0}", qrtext);

这样,我们可以仔细检查发送的内容。

现在,让我们生成我们的QR码。

将QR码生成PNG

接下来,我们要把我们的字符串,编码成一个QR码,然后把它输出到PNG。

因此,我们将静态调用我们先前安装的QRCode库。我们将传入我们想要生成的文本和纠错值。中等的应该就可以了。

C#

var qr = QrCode.EncodeText(qrtext, QrCode.Ecc.Medium);

这就是生成一个QR码的全部内容。但它是SVG格式的。我们需要把它转换成PNG,这样我们就可以显示它。

由于我们在上面添加了位图扩展,现在我们的qr 对象有一个方法,可以将QR码转换成PNG,有几个参数。

我们需要添加一个比例。我使用了10,这似乎产生了一个合适的尺寸。

我使用了1作为边界。

而且我把前景(代码)设置为SKColors.Black,背景设置为SKColors.White。

下面是要输入的代码:

C#

var pngout = qr.ToPng(10, 1, SkiaSharp.SKColors.Black, SkiaSharp.SKColors.White);

好了,现在我们有了我们的QR码。这很容易!现在,让我们把它打包成JSON并发送出去吧

创建一个JSON返回对象

我们已经在public static class GenerateQRCode 。 让我们创建另一个类,它将创建一个简单的对象,当API被调用时,我们可以返回。

就在GenerateQRCode类的外面(最后一个}之前)创建一个ReturnObject类。

这个类将有一个名为Image 的单一属性。这将是一个字符串,我们将把我们的PNG编码为文本放入其中。

C#

public class ReturnObject {
  public string Image { get; set; }
}

现在回到GenerateQRCode类中,让我们回到刚才的位置。我们将创建一个新的ReturnObject。

C#

var ourResult = new ReturnObject{};

现在,我们将把我们的PNG图像转换成一个Base64字符串,并把这个字符串添加到我们的返回对象中。

C#

ourResult.Image = Convert.ToBase64String(pngout);

简单。现在我们只需将我们的POCO(Plain old class object)作为一个新的JsonResult返回,所以它将JSON返回给调用者。

C#

return new JsonResult(ourResult);

这就是它的作用。在大约七行代码中,我们采取了一个字符串,将其转换为QR码,并将其送出大门。

让我们试试吧。

在本地启动该函数

我们将启动这个函数,让它在本地监听。我们将发送一个带查询的GET请求来测试它。

在命令行中输入以下内容:

Shell

func start

来启动这个函数。

你应该看到像这样的东西:

现在我们将发送一个请求到

http://localhost:7071/api/GenerateQRCode

记得我们在代码中指定的参数是qrtext ,所以我将把它加到最后。

http://localhost:7071/api/GenerateQRCode?qrtext="hello world"

我使用Postman来做这个,所以我可以看到JSON渲染出来的:

而我们做的那点日志显示,它正在为 "hello world "进行渲染。 所以步骤很简单:

  • 向我们的URL发送一个GET
  • 附加生成的文本并将其添加到qrtext中
  • 接受JSON。

下面是我们到目前为止输入的所有代码。

C#

public static class QRCodeGen
   {
      [FunctionName("GenerateQRCode")]
       public static async Task<IActionResult> GenerateQRCode(
       [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
       {
           string qrtext = req.Query["qrtext"];
           log.LogInformation("Generating QR Code for {0}", qrtext);

           var qr = QrCode.EncodeText(qrtext, QrCode.Ecc.Medium);
           var pngout = qr.ToPng(10, 1, SkiaSharp.SKColors.Black, SkiaSharp.SKColors.White);

           var ourResult = new ReturnObject{};
           ourResult.Image = Convert.ToBase64String(pngout);
           return new JsonResult(ourResult);
       }
   }
   public class ReturnObject {
       public string Image { get; set; }
   }

这真是太棒了,但我们还没有完成。我们仍然需要部署它。但在这之前,让我们建立一个小型的、简单的JavaScript前端来与这个函数交互。

构建前端

我们希望这个QR码生成器是完全独立的。虽然Azure函数并不是真正为了提供网页而设计的,但这是可能的。在这种情况下,我们可以把它设置好,这样我们就不需要在其他地方托管我们的前端。这只是一个简单的网页,所以让我们来提供它。

首先,我们将创建我们的index.html。

创建一个名为www 的文件夹,并创建一个名为index.html 的文件。

这将是一个超级简单、粗糙的前端--没有什么花哨的东西,只要能完成工作就可以了。

在顶部添加以下内容。

HTML

<!DOCTYPE html>
<html>
<body>

<h2>QR Code Generator</h2>

这就是我们的基本标题。接下来,我们需要添加一个输入,从用户那里获取文本。

HTML

<input id="inputbox" style="width: 250px;" ></input>
<br /><br />

这个输入的id是inputbox,所以我们可以用JavaScript抓取这个文本。我在它后面加了几个换行符,以使其间隔开来。

接下来,我们将创建一个按钮,它将调用一个JavaScript函数。

HTML

<button type="button" onclick="GetQRCode()">Create QR Code</button>

然后,我们将有一个地方,我们将插入QR码。请记住,这将是Base64编码的,这样我们就可以在我们的GetQRCode 函数中用图像填充这个div。

HTML

<div id="demo"></div>

接下来,我们将放入GetQRCode ,该函数会向我们的Azure函数发出一个XMLHttpRequest,并检索JSON。然后解析它,用我们的图片替换 "demo "div。请注意,我们正在添加一个带有头信息的img 标签,这样它就会创建一个我们可以在浏览器中查看的图像。

C#

function GetQRCode() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function () {
    if (this.readyState == 4 && this.status == 200) {
      var ourJSON = JSON.parse(this.responseText);
      document.getElementById("demo").innerHTML = "<img src=\"data:image/png;base64, " + ourJSON.image + "\">";
    }
  };
  input = document.getElementById('inputbox').value xhttp.open("GET", "/api/GenerateQRCode?qrtext=" + input, true);
  xhttp.send();
} <
/script>

很好!所以现在我们有了一个索引页,它将为我们的QRCode生成器绘制一个小的用户界面。

我知道我们可以加入纠错/处理或使用一个库,但我想尽量保持它的简单。

接下来,我们需要用我们的Azure函数来提供这个服务。

提供索引页

Azure函数的目的不是为了成为Web服务器。事实上,Azure静态Web应用做得更好,但我们要尽可能地保持简单。一个单一的Azure函数就可以完成这个任务。

我们可以把index.html文件推送出去,这样它就会被浏览器提供。这为我们的应用程序提供了一个小的界面,如果我们愿意的话,我们可以回头建立一个完整的网络应用,利用这个功能,或者把它添加到一个微服务的捆绑中。

再次打开GenerateQRCode.cs,在我们的类的顶部(在[FunctionName("Form")]上面)让我们添加另一个函数。

我们希望这个函数这次能返回一个HttpResponseMessage。我们仍然要把它变成一个HttpTrigger,采用匿名认证,并传入和以前一样的值。

不过这一次,我们需要传入ExecutionContext context 。这给了我们执行的上下文,所以我们可以在本地文件系统中定位文件,我将在后面解释为什么。

另一个是这将返回HttpResponseMessage而不是IActionResult。

C#

[FunctionName("Form")]          
public static HttpResponseMessage Form([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] 
                                       HttpRequest req, ILogger log, ExecutionContext context){

接下来,我们要打开我们放在www 文件夹中的index.html 文件,并将其作为文本全部读入。这就是执行环境的来源。

我们要打开index.html文件,该文件位于应用程序运行的文件系统的www文件夹中。我们用这行代码来做这件事。

C#

string indexPage = File.ReadAllText(context.FunctionAppDirectory + "/www/index.html");

然后我们将创建一个新的HttpResponseMessage,状态代码为OK(200)。

C#

var result = new HttpResponseMessage(HttpStatusCode.OK);

现在我们需要给它添加一些标题,并在 "内容 "中填入我们从索引文件中读取的文本。

C#

result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
result.Content = new ByteArrayContent(System.Text.Encoding.UTF8.GetBytes(indexPage));

现在我们有了一个带有text/html 头的200 OK消息,而且我们把index.html中的所有文本都添加到头的内容部分。

这是很黑的,但它是有效的。

然后我们简单地返回它。

C#

return result;

所以整个函数看起来像这样:

C#

[FunctionName("Form")]
public static HttpResponseMessage Form(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
    ILogger log, ExecutionContext context)
{

    string indexPage = File.ReadAllText(context.FunctionAppDirectory + "/www/index.html");

    var result = new HttpResponseMessage(HttpStatusCode.OK);

    result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");
    result.Content = new ByteArrayContent(System.Text.Encoding.UTF8.GetBytes(indexPage));

    return result;
}

由于我们引入的这个外部文件(index.html)需要包含在构建中,我们需要将其添加到我们的.csproj文件中。在一个项目组中,加入以下代码。

HTML

<None Update="www\index.html">
     <CopyToOutputDirectory>Always</CopyToOutputDirectory>

我把我的代码和其他的文件发布设置一起加进去了。 保存它,然后让我们再次在本地运行我们的Azure函数。

func start

让我们来看看它是如何工作的。

测试我们的前端

现在我的函数已经在本地运行了,所以我可以直接调出一个网页浏览器来。

http://localhost:7071/api/Form

就可以看到它的全貌了:

因此,我将输入一个URL。 这就是我的QR码,临时生成的。太棒了

让我们把它部署到Azure。

部署我们的应用程序

我现在称这个为 "应用程序",因为它是。我们已经超越了一个简单函数的预期功能,只是为了展示Azure函数的强大。让我们来部署这个,看看它是如何工作的。

使用Azure CLI,键入

az login

你会被引导通过网络浏览器登录Azure。 在Azure控制台中,创建一个新的Azure函数应用。你可以随心所欲地命名它。 选择以代码形式发布,并使用以下运行时间栈。你可以选择任何你想要的区域。 我将选择Windows和消费(无服务器)模式。 我将创建一个新的存储账户,并按 "审查和创建" 记下你的细节: 现在我们需要用Azure CLI来发布。我们将通过使用func ,并指定我们要发布一个Azure functionapp,名称,并加上"-nozip "来告诉该命令我们不是在部署应用程序的压缩包,而是源代码。

外壳

func azure functionapp publish qrcodegen --nozip

完成后,你应该看到类似这样的东西: 你需要登录你的Azure门户,加载功能应用并选择 "配置"。 然后找到WEBSITE_RUN_FROM_PACKAGE ,将值设为0 。这将使我们的函数能够从我们发布的文件中运行。 让我们来看看!

在Azure上运行应用程序

部署后,你应该看到这样的屏幕。 表单 "这个URL将为我们的函数调出用户界面。 而且你可以输入你的网站,并从中创建一个二维码! 而且它还能工作!我们自己的二维码生成器100%从Azure函数中运行。

总结

如果你一直在关注,感谢你的坚持!你现在已经有了一个很酷的项目,并对Azure函数有了更深的了解。这个项目的完整源代码在这里

为网站提供服务并不完全是Azure函数的设计目的,但我希望这是在Azure函数上从头到尾的一个完整解决方案。没有服务器,没有数据库,你也没有几个服务需要跟踪。

我们了解了Azure函数是如何工作的,以及它们可以多么简单。我们在这里没有写多少代码!我们学习了如何用.NET库生成二维码,建立一个小型应用并将其部署到云中。我想尽可能地保持简单,以便进行良好的介绍。如果你要建立一个 "真正的 "应用,我的建议是这样的:

  • 在Azure Static Web Apps或类似服务上托管前端
  • 对输入的错误进行检查
  • 优雅的错误处理和日志记录
  • 将图像推入存储,以便以后检索
  • 设计API,使其也能被其他类型的应用所使用。