You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Function V2部署后函数不显示且触发404问题排查

Azure Function部署后函数不显示且404错误排查与解决

我有一段Azure Function V2风格的HTTP触发器+Blob输出绑定代码,本地运行完全正常——访问http://localhost:7071/api/tfl_blob时,函数会从TFL API获取payload并将数据存入Blob存储。但部署到Azure平台后,部署过程无报错,函数却未出现在Function App中;虽能访问应用文件,但无法触发函数,访问预期格式的URL(https://<function app name>.azurewebsites.net/api/<function name>?code=<function key>)时出现HTTP ERROR 404。

可能原因分析

  • Blob路径静态绑定异常:代码中_blob_path = generate_blob_path()在函数加载阶段执行,生成的是部署时刻的路径。Azure Functions部署时会预加载函数元数据,静态绑定的动态路径会导致绑定逻辑异常,进而影响函数索引识别。
  • 函数索引配置未同步:本地local.settings.json中设置了AzureWebJobsFeatureFlags: EnableWorkerIndexing,但部署到Azure后该配置未同步到Function App的应用设置,导致Python Worker无法正确索引函数。
  • 扩展包与运行时兼容性:host.json中扩展包版本为[4.*, 5.0.0),与Python Function Runtime ~4可能存在版本兼容问题,或扩展包未正确安装。
  • 依赖缺失:部署过程中未正确安装requests等第三方依赖,导致函数加载失败。

解决方法

1. 修正Blob路径为动态绑定

将路径生成逻辑移到函数内部,或使用Azure Functions内置的绑定表达式实现动态路径,避免静态绑定的时机问题:

方案一:函数内动态设置路径

import datetime
import json
import requests
import azure.functions as func
import logging
import uuid

app = func.FunctionApp()

@app.function_name(name="HttpTflBlobOut")
@app.route(route="tfl_blob")
# 先使用占位符定义绑定
@app.blob_output(arg_name="blob",
                 path="bloboutput/temp/temp.json",
                 connection="AzureWebJobsStorage")
def main(req: func.HttpRequest, blob: func.Out[str]) -> func.HttpResponse:
    try:
        # 动态生成Blob路径
        current_datetime = datetime.datetime.now().strftime('%Y-%m-%d')
        unique_id = str(uuid.uuid4())
        blob.set_path(f"bloboutput/{current_datetime}/{unique_id}.json")
        
        # 原有业务逻辑
        result = requests.get('https://api.tfl.gov.uk/line/mode/tube/status',
                              headers={"content-type": "application/json", "charset": "utf-8"})
        logging.info('Python HTTP trigger function processed the API request to TFL')

        since_id = None
        timeline = json.loads(result.text)
        tflLineStatus = []
        for t in timeline:
            if since_id is None:
                since_id = t["id"]
            tflLineStatus.append({
                "linename": t["id"],
                "linestatus": t["lineStatuses"][0]["statusSeverityDescription"],
                "timestamp": t["created"]
            })

        if since_id is None:
            since_id = req.state.since_id

        ans = {
            "state": {since_id: since_id},
            "schema": {"tflLineStatus": {"primary_key": ["linename"]}},
            "insert": {"tflLineStatus": tflLineStatus},
            "hasMore": False
        }

        payload = json.dumps(ans, indent=4)
        blob.set(payload)
        return func.HttpResponse(f"Function executed successfully", status_code=200)
    except Exception as e:
        logging.error(f"Error: {str(e)}")
        return func.HttpResponse("Internal Server Error", status_code=500)

方案二:使用内置绑定表达式

直接利用Azure Functions的绑定表达式自动生成动态路径,无需手动处理:

@app.blob_output(arg_name="blob",
                 path="bloboutput/{DateTimeNow:yyyy-MM-dd}/{rand-guid}.json",
                 connection="AzureWebJobsStorage")

2. 同步应用设置到Azure

在Azure Portal的Function App中,进入配置 > 应用设置,确认以下配置存在且正确:

  • FUNCTIONS_WORKER_RUNTIME: python
  • AzureWebJobsFeatureFlags: EnableWorkerIndexing
  • FUNCTIONS_EXTENSION_VERSION: ~4
  • AzureWebJobsStorage: 对应存储账户的连接字符串
  • APPLICATIONINSIGHTS_CONNECTION_STRING: 对应应用洞察的连接字符串

3. 检查扩展包与依赖

  • 确认host.json的扩展包版本与运行时兼容,可锁定到稳定版本:
    {
      "version": "2.0",
      "logging": {
        "applicationInsights": {
          "samplingSettings": {
            "isEnabled": true,
            "excludedTypes": "Request"
          }
        }
      },
      "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[4.15.0, 5.0.0)"
      }
    }
    
  • 确保项目根目录存在requirements.txt,包含所有依赖:
    azure-functions
    requests
    
    部署时Azure会自动安装这些依赖。

4. 排查部署与日志

  • 进入Function App的部署中心,确认所有代码文件已正确上传。
  • 查看日志流,搜索函数加载阶段的错误信息,比如绑定失败、依赖缺失等。

原始代码参考

函数代码(原版本)

import datetime
import json
import requests
import azure.functions as func
import logging
import uuid

app = func.FunctionApp()


def generate_blob_path():
    current_datetime = datetime.datetime.now()
    date_str = current_datetime.strftime('%Y-%m-%d')
    unique_id = str(uuid.uuid4())
    blob_path = f"bloboutput/{date_str}/{unique_id}.json"
    return blob_path


_blob_path = generate_blob_path()


@app.function_name(name="HttpTflBlobOut")
@app.route(route="tfl_blob")
@app.blob_output(arg_name="blob",
                 path=_blob_path,
                 connection="AzureWebJobsStorage")
def main(req: func.HttpRequest, blob: func.Out[str]) -> func.HttpResponse:
    try:
        result = requests.get('https://api.tfl.gov.uk/line/mode/tube/status',
                              headers={"content-type": "application/json", "charset": "utf-8"})

        logging.info('Python HTTP trigger function processed the API request to TFL')

        since_id = None
        timeline = json.loads(result.text)

        tflLineStatus = []
        for t in timeline:
            if since_id is None:
                since_id = t["id"]

            tflLineStatus.append({
                "linename": t["id"],
                "linestatus": t["lineStatuses"][0]["statusSeverityDescription"],
                "timestamp": t["created"]
            })

        if since_id is None:
            since_id = req.state.since_id

        ans = {
            "state": {
                since_id: since_id
            },
            "schema": {
                "tflLineStatus": {
                    "primary_key": ["linename"]
                }
            },
            "insert": {
                "tflLineStatus": tflLineStatus
            },
            "hasMore": False
        }

        logging.info('Payload is constructed')

        payload = json.dumps(ans, indent=4)
        logging.info('Payload is converted to a string')
        blob.set(payload)

        return func.HttpResponse(f"Function executed successfully", status_code=200)
    except Exception as e:
        logging.error(f"Error: {str(e)}")
        return func.HttpResponse("Internal Server Error", status_code=500)

host.json(原版本)

{
  "version": "2.0",
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  }
}

local.settings.json(原版本)

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "python",
    "AzureWebJobsFeatureFlags": "EnableWorkerIndexing",
    "AzureWebJobsStorage": "<匹配存储账户连接字符串并在Azure函数上设置>",
    "FUNCTIONS_EXTENSION_VERSION": "~4",
    "APPLICATIONINSIGHTS_CONNECTION_STRING": "<匹配Azure上的函数配置>"
  },
  "ConnectionStrings": {}
}

内容的提问来源于stack exchange,提问作者Peter Osztodi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:15:54