【问题标题】:How to POST attachment to JIRA using REST API?如何使用 REST API 将附件发布到 JIRA?
【发布时间】:2012-08-06 20:23:39
【问题描述】:

如何在 C# 中使用 JIRA REST API 和 HttpWebRequest 将附件 POST 到 JIRA?

来自documentation under /rest/api/2/issue/{issueIdOrKey}/attachments

发布

为问题添加一个或多个附件。

此资源需要一个多部分的帖子。媒体类型的 multipart/form-data 在 RFC 1867 中定义。大多数客户端库都有使处理多部分帖子变得简单的类。例如,在 Java 中,Apache HTTP 组件库提供了一个 MultiPartEntity,使得提交多部分 POST 变得简单。

为了防止 XSRF 攻击,因为这个方法接受 multipart/form-data,所以它上面有 XSRF 保护。这意味着你必须在请求中提交一个 X-Atlassian-Token: nocheck 的 header,否则会被阻塞。

包含附件的multipart/form-data参数的名称必须是“文件”

上传名为“myfile.txt”的文件以发出 REST-123 的简单示例:

curl -D- -u admin:admin -X POST -H "X-Atlassian-Token: nocheck" -F "file=@myfile.txt" http://myhost.test/rest/api/2/issue/TEST-123/attachments


我有

foreach (JIRAAttachments attachm in attachments.attachments)
{
    request = HttpWebRequest.Create(
                  logInformation.GetUri() + "/rest/api/2/issue/" + key + "/attachments"
              ) as HttpWebRequest;
    request.Headers.Add("Authorization: Basic " + logInformation.GetEncodeAuthentication());
    request.Method = "POST";
    request.ContentType = "multipart/form-data";
    request.Headers.Add("X-Atlassian-Token: nocheck file=@" + Path.GetFullPath(@"..\Attachments\" + attachm.filename));
    request.KeepAlive = true;
    request.Proxy = wp;
    response = (HttpWebResponse)request.GetResponse();
    Stream s = response.GetResponseStream();
    FileStream fs = new FileStream(Path.GetFullPath(@"..\Attachments\" + attachm.filename), FileMode.Open);
    byte[] write = new byte[256];
    int count = fs.Read(write, 0, write.Length);
    while (count > 0)
    {
        s.Write(write, 0, count);
        count = fs.Read(write, 0, write.Length);
    }
    fs.Close();
    s.Close();
    response.Close();
}

但它返回一个 404 错误...

【问题讨论】:

标签: c# rest jira


【解决方案1】:

解决了你的问题:

var boundary = string.Format("----------{0:N}", Guid.NewGuid());
System.IO.MemoryStream content = new MemoryStream();
var writer = new StreamWriter(content);
foreach (var att in attachments)
{

    writer.WriteLine("--{0}", boundary);
    writer.WriteLine("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", "file", Path.GetFileName(att["filename"]));
    writer.WriteLine("Content-Type: {0}", att.ContentType);
    writer.WriteLine();
    writer.Flush();
    att.Stream.CopyTo(content);
    writer.WriteLine();
}
writer.WriteLine("--" + boundary + "--");
writer.Flush();
content.Seek(0, SeekOrigin.Begin);


HttpWebRequest oRequest = null;
oRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format(RestBaseURI + "issue/{0}/attachments", item.Key));
oRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
oRequest.Method = "POST";
oRequest.Headers.Add("Authorization", AuthData);
oRequest.Headers.Add("X-Atlassian-Token", "nocheck");
oRequest.UseDefaultCredentials = true;
oRequest.KeepAlive = true;
oRequest.ContentLength = content.Length;

using (var oStream = oRequest.GetRequestStream())
{
    content.CopyTo(oStream);
}

using (var oResponse = (HttpWebResponse)oRequest.GetResponse())
{
    using (var reader = new StreamReader(oResponse.GetResponseStream()))
    {
        var responseData = reader.ReadToEnd();
        var data = JObject.Parse(responseData);
    }
}

PS:Thanks2mod 删除我之前的帖子!不错...

【讨论】:

  • 谢谢!非常有用。最后我只得到一个异常 var data = JObject.Parse(responseData);它说它不是 json 对象。但是检查它定义的 responseData 。有什么想法吗??
【解决方案2】:

OP 的代码中有几个错误。

使用@mabu 提供的sn-p 和我在http://www.briangrinstead.com/blog/multipart-form-post-in-c 上找到的代码,这是一个*功能** 代码块,可以将附件上传到Jira。

public bool AddAttachments(string issueKey, IEnumerable<string> filePaths)
{
    string restUrl = Jira.FormatRestUrl(m_JiraId, true);
    string issueLinkUrl = String.Format("{0}/issue/{1}/attachments", restUrl, issueKey);

    var filesToUpload = new List<FileInfo>();
    foreach (var filePath in filePaths)
    {
        if (!File.Exists(filePath))
        {
            Jira.LogError("File '{0}' doesn't exist", filePath);
            return false;
        }

        var file = new FileInfo(filePath);
        if (file.Length > 10485760) // TODO Get Actual Limit
        {
            Jira.LogError("Attachment too large");
            return false;

        }

        filesToUpload.Add(file);
    }

    if (filesToUpload.Count <= 0)
    {
        Jira.LogWarning("No file to Upload");
        return false;
    }

    return PostMultiPart(issueLinkUrl, filesToUpload);
}

private Boolean PostMultiPart(string restUrl, IEnumerable<FileInfo> filePaths)
{
    HttpWebResponse response = null;
    HttpWebRequest request = null;

    try
    {
        var boundary = string.Format("----------{0:N}", Guid.NewGuid());
        var content = new MemoryStream();
        var writer = new StreamWriter(content);

        foreach (var filePath in filePaths)
        {
            var fs = new FileStream(filePath.FullName, FileMode.Open, FileAccess.Read);
            var data = new byte[fs.Length];
            fs.Read(data, 0, data.Length);
            fs.Close();

            writer.WriteLine("--{0}", boundary);
            writer.WriteLine("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"", filePath.Name);
            writer.WriteLine("Content-Type: application/octet-stream");
            writer.WriteLine();
            writer.Flush();

            content.Write(data, 0, data.Length);

            writer.WriteLine();
        }

        writer.WriteLine("--" + boundary + "--");
        writer.Flush();
        content.Seek(0, SeekOrigin.Begin);

        request = WebRequest.Create(restUrl) as HttpWebRequest;
        if (request == null)
        {
            Jira.LogError("Unable to create REST query: {0}", restUrl);
            return false;
        }

        request.Method = "POST";
        request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
        request.Accept = "application/json";
        request.Headers.Add("Authorization", "Basic " + m_EncodedCredential);
        request.Headers.Add("X-Atlassian-Token", "nocheck");
        request.ContentLength = content.Length;

        using (Stream requestStream = request.GetRequestStream())
        {
            content.WriteTo(requestStream);
            requestStream.Close();
        }

        using (response = request.GetResponse() as HttpWebResponse)
        {
            if (response.StatusCode != HttpStatusCode.OK)
            {
                var reader = new StreamReader(response.GetResponseStream());
                Jira.LogError("The server returned '{0}'\n{1}", response.StatusCode, reader.ReadToEnd());
                return false;
            }

            return true;
        }
    }
    catch (WebException wex)
    {
        if (wex.Response != null)
        {
            using (var errorResponse = (HttpWebResponse)wex.Response)
            {
                var reader = new StreamReader(errorResponse.GetResponseStream());
                Jira.LogError("The server returned '{0}'\n{1}).", errorResponse.StatusCode, reader.ReadToEnd());
            }
        }

        if (request != null)
        {
            request.Abort();
        }

        return false;
    }
    finally
    {
        if (response != null)
        {
            response.Close();
        }
    }
}

【讨论】:

    【解决方案3】:

    我真的不想处理所有boundary 的东西,所以这是我的尝试。这适用于Confluence,其 API 看起来与 Jira 相同。

    感谢ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient 的 Michael Teper 和杰夫·卡隆(上图)。

    var contents = "some long HTML that I wanted to upload";
    var fileName = "Some fancy file name.html";
    
    using (var client = new HttpClient())
    {
        var uri = new Uri(URL);
    
        client.BaseAddress = new Uri(URL);
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
        client.DefaultRequestHeaders.Authorization = authorization;
        client.DefaultRequestHeaders.Add("X-Atlassian-Token", "nocheck");
    
        var uriPath = String.Format(AttachmentPath, pageId);
    
        var content = new MultipartFormDataContent();
        var fileContent = new StringContent(contents);
        // also tested to work: 
        // var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes(contents));
        content.Add(fileContent, "file", fileName);
    
        var response = await client.PostAsync(uriPath, content);
        if (response.IsSuccessStatusCode)
        {
            return TaskResult.Success(null, response.ReasonPhrase);
        }
        else
        {
            return TaskResult.Failure("Service responded with Status Code: " + response.StatusCode + Environment.NewLine + "Reason Phrase: " + response.ReasonPhrase);
        }
    }
    

    【讨论】:

      【解决方案4】:

      您也可以使用 Restsharp,如下所示

      using System;
      using System.Collections.Generic;
      using System.IO;
      using System.Net;
      using Jira
      using RestSharp;
      using RestSharp.Authenticators;
      
      namespace Jira
      {
          class Program
          {
            static void Main(string[] args)
            {
              var client = new RestClient("http://{URL}/rest/api/2");
              var request = new RestRequest("issue/", Method.POST);
      
              client.Authenticator = new HttpBasicAuthenticator("user", "pass");
      
              var issue = new Issue
              {
                  fields =
                      new Fields
                      {
                          description = "Issue Description",
                          summary = "Issue Summary",
                          project = new Project { key = "KEY" }, 
                          issuetype = new IssueType { name = "ISSUE_TYPE_NAME" }
                      }
              };
      
              request.AddJsonBody(issue);
      
              var res = client.Execute<Issue>(request);
      
              if (res.StatusCode == HttpStatusCode.Created)
              {
                  Console.WriteLine("Issue: {0} successfully created", res.Data.key);
      
                  #region Attachment            
                  request = new RestRequest(string.Format("issue/{0}/attachments", res.Data.key), Method.POST);
      
                  request.AddHeader("X-Atlassian-Token", "nocheck");
      
                  var file = File.ReadAllBytes(@"C:\FB_IMG_1445253679378.jpg");
      
                  request.AddHeader("Content-Type", "multipart/form-data");
                  request.AddFileBytes("file", file, "FB_IMG_1445253679378.jpg", "application/octet-stream");
      
                  var res2 = client.Execute(request);
      
                  Console.WriteLine(res2.StatusCode == HttpStatusCode.OK ? "Attachment added!" : res2.Content);
                  #endregion
              }
              else
                  Console.WriteLine(res.Content);
            }
          }
      
          public class Issue
          {
              public string id { get; set; }
              public string key { get; set; }
              public Fields fields { get; set; }
          }
      
          public class Fields
          {
              public Project project { get; set; }
              public IssueType issuetype { get; set; }
              public string summary { get; set; }
              public string description { get; set; }        
          }
      
          public class Project
          {
              public string id { get; set; }
              public string key { get; set; }
          }
      
          public class IssueType
          {
              public string id { get; set; }
              public string name { get; set; }
          }
      }
      

      整个代码在要点https://gist.github.com/gandarez/c2c5b2b27dbaf62a0d634253529bcb59

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-02-24
        • 2020-06-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多