简体   繁体   English

无法将附件正确上传到 Azure DevOps API(0kb 结果)

[英]Unable to upload attachment to Azure DevOps API correctly (0kb result)

I'm trying to upload attachments to work items in Azure DevOps using the REST API.我正在尝试使用 REST API 将附件上传到 Azure DevOps 中的工作项。 However, while I can get the attachment "uploaded" and attached to the work item, the attachment is always 0KB in size, both in the UI and when I download it.但是,虽然我可以将附件“上传”并附加到工作项,但附件的大小始终为 0KB,无论是在 UI 中还是在我下载它时。

The API looks fairly straightforward, and I've not had issues with the dozen other APIs I've used. API 看起来相当简单,而且我使用过的其他十几个 API 都没有问题。 I just can't figure out where this is going wrong.我只是想不通这是哪里出了问题。 Here's the code I'm using for this:这是我为此使用的代码:

import os
import sys
import requests


_credentials = ("user@example.com", "password")

def post_file(url, file_path, file_name):

    file_size = os.path.getsize(file_path)

    headers = {
        "Accept": "application/json",
        "Content-Size": str(file_size),
        "Content-Type": "application/octet-stream",
    }

    request = requests.Request('POST', url, headers=headers, auth=_credentials)
    prepped = request.prepare()

    with open(file_path, 'rb') as file_handle:
        prepped.body = file_handle.read(file_size)

    return requests.Session().send(prepped)


def add_attachment(path_to_attachment, ticket_identifier):
    filename = os.path.basename(path_to_attachment)

    response = post_file(
        f"https://[instance].visualstudio.com/[project]/_apis/wit/attachments?uploadType=Simple&fileName={filename}&api-version=1.0",
        path_to_attachment,
        filename
    )

    data = response.json()
    attachment_url = data["url"]

    patch_result = requests.patch(
        f"https://[instance].visualstudio.com/[project]/_apis/wit/workitems/{ticket_identifier}?api-version=4.1",
        auth=_credentials, 
        headers={
            "Accept": "application/json",
            "Content-Type": "application/json-patch+json",
        }, 
        json=[
            {
                "op": "add",
                "path": "/relations/-",
                "value": {
                    "rel": "AttachedFile",
                    "url": attachment_url
                },
            }
        ]
    )

    print(patch_result)
    print(patch_result.text)

add_attachment(sys.argv[1], sys.argv[2])

I've tried setting/removing/varying every possible header value I can think of.我试过设置/删除/改变我能想到的每个可能的标头值。 I've tried using the files attribute that's on the post method in requests (but dropped it because it set Content-Disposition, but all examples I've seen don't use that), I've tried setting the area path parameter, I've tried everything I can think of, but nothing has made any difference.我试过在requests使用post方法上的files属性(但因为它设置了 Content-Disposition 而删除它,但我见过的所有示例都没有使用它),我试过设置区域路径参数,我已经尝试了我能想到的一切,但没有任何区别。

I've even used Fiddler to watch how the actual site does it, then copied the headers to a new request in Python and sent that and I'm still seeing the 0kb result.我什至使用 Fiddler 来观察实际站点的工作方式,然后将标头复制到 Python 中的新请求并发送,但我仍然看到 0kb 结果。

I'm pretty much out of ideas at this point, so if anyone knows where I may be going wrong, it would be much appreciated!在这一点上我几乎没有想法,所以如果有人知道我可能出错的地方,将不胜感激!

The answer to this wasn't obvious.这个问题的答案并不明显。 It was the second call to link the attachment to the work item that had the bug.这是将附件链接到有错误的工作项的第二次调用。 If a comment isn't specified, it doesn't link correctly.如果未指定评论,则无法正确链接。 ie This code:即此代码:

json=[
    {
        "op": "add",
        "path": "/relations/-",
        "value": {
            "rel": "AttachedFile",
            "url": attachment_url
        },
    }
]

Should have been:本来应该:

json=[
    {
        "op": "add",
        "path": "/relations/-",
        "value": {
            "rel": "AttachedFile",
            "url": attachment_url,
            "attributes": {
                "comment": ""
            }
        },
    }
]

This isn't documented, nor is it expected that you'd get a 0KB attachment upload if you don't specify a comment in the linking phase.这没有记录在案,如果您没有在链接阶段指定评论,也不会期望您获得 0KB 附件上传。 No other link types need a comment.没有其他链接类型需要注释。 I'm going to raise this issue with the documentation maintainers.我将向文档维护者提出这个问题。

I've been working on this as well and found a solution.我也一直在研究这个,并找到了解决方案。 You have to add the filesize parameter in the json.您必须在 json 中添加 filesize 参数。 You don't have to put a comment to get size to show.您不必发表评论即可显示大小。

Note it appears that DevOps rounds to the nearest 1,000 (my test file was 325 and it shows as 1K in DevOps)请注意,DevOps 似乎四舍五入到最接近的 1,000(我的测试文件是 325,它在 DevOps 中显示为 1K)

    file_size = os.path.getsize(file_path)

    json = [
        {
            "op": "add",
            "path": "/relations/-",
            "value": {"rel": "AttachedFile", "url": attachment.url,
                "attributes": {"comment": "DevOps Test", "resourceSize": file_size},
             }
        }
    ]

Hope this helps someone!希望这可以帮助某人!

Your post file function should become:您的发布文件功能应变为:

def post_file(url, file_path, file_name):
    file_size = os.path.getsize(file_path)

    headers = {
        "Accept": "application/json",
        "Content-Size": str(file_size),
        "Content-Type": "application/octet-stream",
    }
    files = {'file': open(file_path, 'rb')}
    r = requests.post(url, files=files, headers=headers, auth=(username, token))
    return r

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM