我正在尝试使用 Azure ShareFile 客户端通过函数应用程序将数据从 SQL Server 表导出到 XLSX 文件。当我在本地 VSCode 中运行代码时,文件已成功创建。我相信这一成功可以归因于我是存储帐户的所有者。当代码在计算机上执行时,Azure 使用我的登录名进行身份验证。但是,部署到云的 Azure 函数应用程序中导出失败并出现 403 授权错误。
初始化ShareFile客户端的代码如下:
def getFileClient(filePath):
accountName = accountKey = os.environ["AZURE_STORAGE_ACCOUNT_NAME"]
accountKey = os.environ["AZURE_STORAGE_ACCOUNT_KEY"]
connectStr = os.environ["AZURE_STORAGEFILE_CONNECTIONSTRING"]
shareName = "dev"
sasToken = generate_account_sas(
account_name=accountName,
account_key=accountKey,
resource_types=ResourceTypes(service=True, object=True),
permission=AccountSasPermissions(read=True, write=True),
expiry=datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=1),
services=Services(fileshare=True)
)
shareClient = ShareClient.from_connection_string(conn_str=connectStr, share_name=shareName, credential=sasToken)
# Get a reference to the file
fileClient = shareClient.get_file_client(filePath)
return(fileClient)
导出数据到XLSX文件的代码如下:
XLBytes = BytesIO()
dataMartDF[export_cols].to_excel(XLBytes, index=False)
XLBytes.seek(0)
countyDispFC.create_file(size=XLBytes.getbuffer().nbytes)
countyDispFC.upload_file(XLBytes)
其中 CountyDispFC 是 getFileClient 函数返回的文件客户端。
通过 https 调用该函数时会记录以下错误: 错误日志摘录
请注意,网络设置包括“从选定的虚拟网络和 IP 地址启用”。我已经添加了我的本地机器的IP地址和功能应用程序的公共IP地址。
我还创建了一个托管身份,将其分配给函数应用程序,并授予其存储帐户中的存储文件特权贡献者角色(IAM 中的托管身份角色)。我更愿意使用此托管身份进行访问,但当我尝试创建凭证对象并在 ShareClient 函数中使用它时,遇到了“需要 token_intent”错误。
我错过了什么?
网络设置包括“从选定的虚拟网络和 IP 地址启用”。我已添加本地计算机的 IP 地址和函数应用程序的公共 IP 地址。没有其他网络设置、虚拟网络、专用端点等
设置此设置后,您需要将存储帐户和功能连接到虚拟网络,然后只有它才能工作,下面的方法对我有用:
首先,创建一个 Function 应用并启用托管身份:
然后将V-net链接到存储帐户:
现在将 V-net 链接到 Function App :
单击“未配置”:
链接后:
注意:确保存储帐户、功能应用程序和 vnet 位于同一位置。
建立从 Function 应用程序到存储帐户的连接,您可以在 Function 应用程序子网中启用 Microsoft.storage 服务端点:
部署以下代码:
import os
import logging
from io import BytesIO
import azure.functions as func
import pandas as ch
from azure.identity import DefaultAzureCredential
from azure.storage.fileshare import ShareClient
def ri_gt_cl(file_path):
ri_acc_nme = "tset123"
ri_cs="DefaultEndpointsProtocol=https;AccountName=filehh;AccountKey=/aQKGeeEsa43klLpgjQ==;EndpointSuffix=core.windows.net"
rith_file_share = "rithfile"
ri_scl = ShareClient(
account_url=f"https://{ri_acc_nme}.file.core.windows.net/",
conn_str=ri_cs,
share_name=rith_file_share
)
r_ch = ri_scl.get_file_client(file_path)
return r_ch
import os
import logging
from io import BytesIO
import azure.functions as func
import pandas as ch
from azure.storage.fileshare import ShareClient
def ri_gt_cl(file_path):
ri_cs = "DefaultEndpointsProtocol=https;AccountName=tset123;AccountKey=d+t5237NGVidW+AStjkzsFA==;EndpointSuffix=core.windows.net"
ri_file_shr_name = "rithfile"
risl = ShareClient.from_connection_string(
conn_str=ri_cs,
share_name=ri_file_shr_name
)
ri_fcl = risl.get_file_client(file_path)
return ri_fcl
def ri_up():
ri_dt = {
"Name": ["Rithwik", "Chotu"],
"Age": [8, 7]
}
rid = ch.DataFrame(ri_dt)
ri_ex_b = BytesIO()
rid.to_excel(ri_ex_b, index=False)
ri_ex_b.seek(0)
rifp = "rithtest.xlsx"
rifl = ri_gt_cl(rifp)
fs = ri_ex_b.getbuffer().nbytes
rifl.create_file(size=fs)
rifl.upload_file(ri_ex_b)
return f"Hello Rithwik, File Uploaded '{rifp}'"
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info("Hello Rithwik, Function Started")
try:
ri_out = ri_up()
return func.HttpResponse(
f"Success: {ri_out}",
status_code=200
)
except Exception as ri:
logging.error(f"Hello Rithwik, there is an error: {str(ri)}")
return func.HttpResponse(f"Hello Rithwik, Error is: {str(ri)}",status_code=500)
输出:
执行的功能应用程序:
在存储帐户中下载文件:
文件: