我最近开始研究 Azure 并想实际运行一些东西,所以我开始使用 Azure Functions。
这篇文章的作用
- 为 Azure Functions (Java) 构建本地开发环境使用
- 命令部署到 Azure
微软文档我们将根据实际构建
这类文章还有很多,但我想留下我偶然发现的要点。
*此内容适用于有Java开发经验的人。
目录
操作环境
工作环境如下。
- 操作系统
- Windows 11 专业版 (21H2)
- Ubuntu 20.04 (WLS)
* 使用旧版本,因为最新版本不起作用
- JDK
-
开放JDK 11
*JDK的安装不包括在程序中
-
开放JDK 11
安装 Azure 核心工具
-
视窗
安装程序安装。
-
Linux
-
包完整性验证。
curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg -
配置 apt 源列表。
-
对于 Ubuntu
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-$(lsb_release -cs)-prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list' -
对于 Debian
sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/debian/$(lsb_release -rs | cut -d'.' -f 1)/prod $(lsb_release -cs) main" > /etc/apt/sources.list.d/dotnetdev.list'
-
-
安装
sudo apt-get update sudo apt-get install azure-functions-core-tools-4
-
安装 Azure CLI
-
视窗
安装程序安装。
-
Linux
sudo apt install azure-cli安装的版本在我的工作环境(Ubuntu20.04)好像比较旧,所以这里我安装它是指
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
如果执行以下命令显示版本,则安装完成。
az --version
安装 Maven
-
视窗
参考本文安装。
-
Linux
sudo apt install maven
创建一个 Maven 项目
-
项目创建
mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=11您可以在
-DjavaVersion=11部分中指定java 版本。*截至2022/10/12,
8和11可以选择(17是预览功能) -
出现提示时输入以下内容。
环境 价值 解释 组 ID com.azure_functions 唯一标识项目的值。 工件 ID 天蓝色函数 没有版本号的 jar 名称。 版本 1.0-快照 罐子版本。选择默认。 包裹 com.azure_functions 包裹名字。默认值与 groupId 相同。 -
如果显示“BUILD SUCCESS”,请输入“Y”并确定。
创造了什么azure-functions/ ├── host.json ├── local.settings.json ├── pom.xml └── src ├── main │ └── java │ └── com │ └── azure_functions │ └── Function.java └── test └── java └── com └── azure_functions ├── FunctionTest.java └── HttpResponseMessageMock.java -
移动到创建的文件夹并使用以下命令进行构建。
mvn clean package启动本地服务器
mvn azure-functions:run如果正常启动,端点会显示如下。
・・・ Functions: HttpExample: [GET,POST] http://localhost:7071/api/HttpExample ・・・函数调用
您可以通过访问显示的端点来调用该函数。
用命令检查
curl http://localhost:7071/api/HttpExample结果Please pass a name on the query string or in the request body带参数调用
curl http://localhost:7071/api/HttpExample?name=AzureLearn结果Hello, AzureLearn函数体中的代码
分钟 c 土壤温度。爪哇public class Function { /** * This function listens at endpoint "/api/HttpExample". Two ways to invoke it * using "curl" command in bash: * 1. curl -d "HTTP Body" {your host}/api/HttpExample * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query" */ @FunctionName("HttpExample") public HttpResponseMessage run( @HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, final ExecutionContext context) { context.getLogger().info("Java HTTP trigger processed a request."); // Parse query parameter final String query = request.getQueryParameters().get("name"); final String name = request.getBody().orElse(query); if (name == null) { return request.createResponseBuilder(HttpStatus.BAD_REQUEST) .body("Please pass a name on the query string or in the request body").build(); } else { return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build(); } } }正在做
- 从正文中获取请求的查询参数或
name。如果无法获取 - name,则返回
Please pass a name on the query string or in the request body作为响应。如果可以获取 - name参数,则返回
Hello, <nameの値>作为响应。使用
@FunctionName注释指定函数名称。 (部署到 Azure 的名称)
如果route未在下面描述的@HttpTrigger注释中指定,/api/<関数名>将成为端点。
您可以通过指定route来自定义端点。使用
@HttpTrigger注解设置触发器。在示例中,它看起来像这样:
环境 设置 解释 姓名 要求 请求或请求正文中函数代码中使用的变量名称。 (……?) 方法 获取,发布 接受请求的 HTTP 方法。
可以在数组中指定多个。授权级别 匿名的 指定调用函数时的授权级别。 - 匿名 - 无需 API 密钥即可访问。
- FUNCTION - 需要特定于函数的 API 密钥。
- 管理员 - 需要主密钥。
有关
@HttpTrigger的更多信息
Azure Functions 中的 HTTP 触发器看代码更改
这很无聊,所以让我们更改代码以返回正确的 JSON 数据。
azure-functions/ ├── host.json ├── local.settings.json ├── pom.xml ------------------------------------ 変更 └── src ├── main │ └── java │ └── com │ └── azure_functions │ ├── Function.java ---------- 変更 │ ├── models │ │ └── TodoItem.java ------ 追加 │ ├── services │ │ └── TodoService.java --- 追加 │ └── utils │ └── JsonUtil.java ------ 追加 └── test └── java └── com └── azure_functions ├── FunctionTest.java └── HttpResponseMessageMock.javapom.xml<dependencies> <dependency> <groupId>com.microsoft.azure.functions</groupId> <artifactId>azure-functions-java-library</artifactId> <version>${azure.functions.java.library.version}</version> </dependency> <!-- ↓追加↓(Lombok使いたかった) --> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.24</version> <scope>provided</scope> </dependency> <!-- JSONシリアライズのカスタマイズ用 --> <dependency> <groupId>com.azure</groupId> <artifactId>azure-core-serializer-json-jackson</artifactId> <version>1.2.22</version> </dependency> <!-- ↑追加↑ -->Function.java(函数体)public class Function { /** * TODO一覧を取得 * * @param request リクエスト * @param context 実行コンテキスト * @return レスポンス */ @FunctionName("fetchTodoItems") public HttpResponseMessage fetchTodoList( @HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS, // エンドポイントを「/api/todo/list」に設定 route = "todo/list") HttpRequestMessage<Optional<String>> request, final ExecutionContext context) { context.getLogger().info("Java HTTP trigger processed a request."); // TODO一覧取得 var todoService = new TodoService(context); List<TodoItem> todoItems = todoService.fetchTodoItems(); // TODO一覧をJSONに変換 var jsonUtil = new JsonUtil(context); String json = jsonUtil.serialize(todoItems); return request.createResponseBuilder(HttpStatus.OK) .header("Content-Type", "application/json;") .body(json).build(); } }- 修改为返回 TODO 列表
- 自定义端点
绊脚点①
在生成最后一个响应的部分,即使
todoItems传递给body(),也会在未经许可的情况下被序列化,但是由于LocalDateTime类型的格式不整齐,所以后面描述的JsonUtil.java尝试传递连载一本。TodoService.java(获取 TODO 列表的类)/** * TODOサービス */ @RequiredArgsConstructor public class TodoService { /** 実行コンテキスト */ private final ExecutionContext context; /** * TODO一覧を取得 * * @return TODO一覧 */ public List<TodoItem> fetchTodoItems() { context.getLogger().info("fetchTodoItems"); // ダミーデータ生成 List<TodoItem> todoItems = List.of( TodoItem.builder() .content("Azureの勉強") .done(false) .createdAt(LocalDateTime.now()) .build(), TodoItem.builder() .content("Javaの勉強") .done(true) .createdAt(LocalDateTime.now()) .build(), TodoItem.builder() .content("TypeScriptの勉強") .done(false) .createdAt(LocalDateTime.now()) .build()); return todoItems; } }TodoItem.java(TODO 容器)@Data @Builder public class TodoItem { /** 内容 */ private String content; /** 完了フラグ */ private boolean done; /** 作成日時 */ private LocalDateTime createdAt; }JsonUtil.java(JSON 转换实用程序)/** * JSON関連のユーティリティ */ @RequiredArgsConstructor public class JsonUtil { /** JSONシリアライズ用のマッパー */ private static final ObjectMapper MAPPER = objectMapper(); /** 実行コンテキスト */ private final ExecutionContext context; private static ObjectMapper objectMapper() { var mapper = new ObjectMapper(); // LocalDateTime用のシリアライザを追加 var javaTimeModule = new JavaTimeModule(); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss"))); mapper.registerModule(javaTimeModule); return mapper; } /** * オブジェクトをJSONに変換 * * @param <T> オブジェクトの型 * @param obj オブジェクト * @return JSON文字列 */ public <T> String serialize(T obj) { try { return MAPPER.writeValueAsString(obj); } catch (JsonProcessingException e) { context.getLogger().severe("オブジェクト→JSONの変換に失敗しました。エラーメッセージ:" + e.getMessage()); throw new IllegalArgumentException(e); } } }部署到 Azure
登录到 Azure
az login执行命令时,浏览器将启动并要求您登录,因此请按照它进行操作。
*仅首次登录即可部署
mvn azure-functions:deploy成功部署后,您将看到端点。
这是/api/todo/list。结果[INFO] HTTP Trigger Urls: [INFO] fetchTodoItems : https://azure-learn-functions796.azurewebsites.net/api/todo/list [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------检查部署结果
创建的资源
在部署期间,会自动创建以下资源。
- 资源组
- 功能应用
- 存储帐户
- 应用服务计划
- 应用程序洞察
pom.xml 中的
build.plugins.plugin.configuration允许您自定义创建资源的配置。设置名称 默认值 解释 应用名称 项目创建时指定的 artifactId + 项目创建的日期和时间 功能应用名称 资源组 java函数组 函数应用所属的资源组名称。 应用服务计划名称 java-functions-app-服务计划 应用服务计划名称 地区 韦斯特斯 待创建资源所属区域 用命令检查
curl https://azure-learn-functions796.azurewebsites.net/api/todo/list结果(为便于阅读而格式化)[ { "content": "Azureの勉強", "done": false, "createdAt": "2022-10-10 18:38:26" }, { "content": "Javaの勉強", "done": true, "createdAt": "2022-10-10 18:38:26" }, { "content": "TypeScriptの勉強", "done": false, "createdAt": "2022-10-10 18:38:26" } ]作为响应,返回了设置为
body()的 JSON。检查 Azure 门户
Azure上部署的功能是Azure 门户你也可以从上面做。
関数アプリ→<関数アプリ名>→関数→<関数名>→コードとテスト→テストと実行
您还可以指定参数、标头和 API 密钥。
执行时,标准错误输出实时显示到屏幕上的控制台。
如果它不起作用,我建议你在这里检查。这可能只是我的环境,但是即使函数本身成功,也会返回 response: 500 。
向 URLhttps://functions.azure.com/api/passthrough发出请求,该请求似乎调用了一个实际函数,该函数返回 500。绊脚点②
Windows (PowerShell) 没有问题,但是在我的环境中,当我在 WSL 上执行部署命令时,出现错误,无法部署。
错误Failed to execute goal com.microsoft.azure:azure-functions-maven-plugin:1.21.0:deploy (default-cli) on project azure-functions: login with (AUTO): device code consumer is not configured.login with (AUTO)和身份验证方法好像是自动选择的,但是好像实际使用的是设备码认证。 (根据错误内容推测)
是不是像“设置了设备认证,但没有设置设备代码”?
因此,要将身份验证方法更改为“Azure CLI”,请将 pom.xml 更改如下。pom.xml<build> <plugins> ・・・ <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-functions-maven-plugin</artifactId> <version>${azure.functions.maven.plugin.version}</version> <configuration> ・・・ <!-- ↓追加↓ --> <auth> <type>azure_cli</type> </auth> <!-- ↑追加↑ --> </configuration> ・・・ </plugin> ・・・ </plugins> </build>当我部署时,我收到以下错误...
错误Failed to execute goal com.microsoft.azure:azure-functions-maven-plugin:1.21.0:deploy (default-cli) on project azure-functions: login with (AZURE_CLI): execute Azure Cli command 'az account list --output json' failed due to error: Process exited with an error: 2 (Exit value: 2).az account list --output json看来命令失败了,所以我尝试单独执行它,但它没有任何问题。最后查不出原因,只好放弃,将认证方式改为“设备码”。
pom.xml<auth> <type>device_code</type> </auth>执行deploy命令时会显示URL和设备代码,在浏览器中打开指定的URL,在弹出的对话框中输入设备代码。
由于这次我正确输入了设备代码,因此我通过了设备代码认证,没有任何问题。[INFO] Auth type: DEVICE_CODE To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code H6HNEDQCQ to authenticate.后记
我偶然发现在 WSL 上进行部署,但我能够轻松地创建和部署一个函数应用程序。
由于这次我们没有使用 API 密钥,任何人都可以访问它,但我们希望将来考虑到这一点。接下来,我想从我这次创建的函数连接到 Azure 托管数据库(MySQL)。
感谢您阅读到最后!
参考
- 从正文中获取请求的查询参数或
原创声明:本文系作者授权爱码网发表,未经许可,不得转载;
原文地址:https://www.likecs.com/show-308629288.html