javascript HttpClient 设置边界与内容类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18500040/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 12:10:03  来源:igfitidea点击:

HttpClient setting boundary with content-type

c#javascripthttpclientcontent-typeboundary

提问by user2548513

I am using javascript to communicate with a third party service. As part of their authentication process they need the "multipart/form" body of the post message including an image to be encrypted in md5, this is added to a string including the date, and a few other things and then a HMAc/SHA1 run on it. So in the end they have the multipart body, the date and the authentication hash in order to authenticate and then read the image.

我正在使用 javascript 与第三方服务进行通信。作为身份验证过程的一部分,他们需要发布消息的“multipart/form”正文,包括要在 md5 中加密的图像,将其添加到包含日期和其他一些内容的字符串中,然后运行 ​​HMAc/SHA1在上面。因此,最终他们拥有多部分正文、日期和身份验证哈希,以便进行身份验证然后读取图像。

This works fine for all mobile devices except for windowsPhone .. (I know, a problem with IE... who would have thought?). their httpwebrequest does not include a 'Date' header .. so no authentication. This means that I have to go native for windows phone and use the newly released httpclient code in C#. Now I am a C# noob so this is possibly where the easy solution is. I have gotten the authentication to work by passing pretty much everything to c# and just doing the post using c# but they cannot read the body because the only way I have found to send the boundary is when defining the content as multipartformDatacontent and sending the content that way changes the body so the authentication failes.

这适用于所有移动设备,除了 windowsPhone ..(我知道,IE 的问题......谁会想到?)。他们的 httpwebrequest 不包含“日期”标头..所以没有身份验证。这意味着我必须在 Windows 手机上使用本机并在 C# 中使用新发布的 httpclient 代码。现在我是 C# 菜鸟,所以这可能是最简单的解决方案。我已经通过将几乎所有内容传递给 c# 并仅使用 c# 执行帖子来获得身份验证,但他们无法读取正文,因为我发现发送边界的唯一方法是将内容定义为 multipartformDatacontent 并发送内容方式更改正文,因此身份验证失败。

my javascript is something like:

我的 javascript 是这样的:

var boundary = "------------ThIs_Is_tHe_bouNdaRY_";
var part1Array = [];
var part1 = "--"+boundary + "\r\n"+
    "Content-Disposition: form-data; name=\"image\"\r\n"+
    "Content-Type: image/jpg\r\n"+
    "\r\n";
var part3Array = [];
var part3 = "\r\n" + boundary +"--";
for(var p1=0; p1<part1.length; p1++){
    part1Array.push(part1.charCodeAt(p1));
}
for(var p3=0; p3<part3.length; p3++){
    part3Array.push(part3.charCodeAt(p3));
}
var bodyContent = part1Array.concat(imageArray,part3Array);

//hash this

var authMessage = bodyContentHash +"\n"+ contentType +"\n"+ todayString +"\n"+ pathandstuff;
// -hmac -sha1 -base64

and the c# is:

而 c# 是:

HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, path);

request.Headers.Date = DateTime.ParseExact(todaydate, "ddd',' dd MMM yyyy HH:mm:ss 'GMT'", new CultureInfo("en-US"), DateTimeStyles.AssumeUniversal);
request.Headers.Add("Accept", "application/json; charset=utf-8");
request.Headers.Add("Authorization", auth);

byte[] body = Convert.FromBase64String(bodyData);
request.Content = new ByteArrayContent(body);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
request.Content.Headers.Add("boundary", "------------ThIs_Is_tHe_bouNdaRY_");

HttpResponseMessage response = client.SendAsync(request).Result;
string resultCode = response.StatusCode.ToString();
string responseBodyAsText = await response.Content.ReadAsStringAsync();

This pretty much works.. the body content is correct as are the headers .. all except the content type header which should be:

这几乎有效..正文内容和标题一样正确..除了内容类型标题应该是:

request.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data, boundary=------------ThIs_Is_tHe_bouNdaRY_");

Except that this throws a System.FormatException error.

除了这会引发 System.FormatException 错误。

回答by Buzzrick

We solved this by manually clearing and re-adding the content type without validation it seems that the MediaTypeHeaderValue() class doesn't like the boundary tags.

我们通过在没有验证的情况下手动清除和重新添加内容类型来解决这个问题,似乎 MediaTypeHeaderValue() 类不喜欢边界标签。

instead of using :

而不是使用:

content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data; boundary=----FLICKR_MIME_20140415120129--");

we did the following:

我们做了以下工作:

content.Headers.Remove("Content-Type");
content.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=----FLICKR_MIME_20140415120129--");

Once we made this change it all worked correctly.

一旦我们进行了此更改,它就可以正常工作。

(Note that this is on WinRT if that makes any difference)

(请注意,如果有任何区别,这是在 WinRT 上)

回答by user553838

with HttpClient

使用 HttpClient

 request.Content.Headers.Add("ContentType", "multipart/form-data, boundary=------------ThIs_Is_tHe_bouNdaRY_");

you can use HttpWebRequest

你可以使用 HttpWebRequest

 myHttpWebRequest.Date = DateTime.Now;
 myHttpWebRequest.ContentType = "multipart/form-data, boundary=------------ThIs_Is_tHe_bouNdaRY_";

回答by arik

I post my code here, maybe this will help anyone else struggling as I did, on my case this works and upload a file to my account (not a banking but a secure cloud file product)

我在这里发布我的代码,也许这会帮助其他像我一样挣扎的人,在我的情况下,这有效并将文件上传到我的帐户(不是银行,而是安全的云文件产品)

 public  string UploadFile(string endpointUrl, string filePath, string accessToken)
    {

        FileStream fs = null;
        Stream rs = null;
        string result = "";
        try
        {

            string uploadFileName = System.IO.Path.GetFileName(filePath);

            fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);

            var request = (HttpWebRequest)WebRequest.Create(endpointUrl);
            request.Method = WebRequestMethods.Http.Post;
            request.AllowWriteStreamBuffering = false;
            request.SendChunked = true;
            String CRLF = "\r\n"; // Line separator required by multipart/form-data.        
            long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();

            string boundary = timestamp.ToString("x");
            request.ContentType = "multipart/form-data; boundary=" + boundary;

            request.Headers.Add("Authorization", "Bearer " + accessToken);                             

            long bytesAvailable = fs.Length;
            long maxBufferSize = 1 * 1024 * 1024;


            rs = request.GetRequestStream();
            byte[] buffer = new byte[50];
            int read = 0;

            byte[] buf = Encoding.UTF8.GetBytes("--" + boundary + CRLF);
            rs.Write(buf, 0, buf.Length);

            buf = Encoding.UTF8.GetBytes("Content-Disposition: form-data; name=\"body\"; filename=\"" + uploadFileName + "\"" + CRLF);                
            rs.Write(buf, 0,buf.Length);

            buf = Encoding.UTF8.GetBytes("Content-Type: application/octet-stream;" + CRLF);
            rs.Write(buf, 0, buf.Length);

            buf = Encoding.UTF8.GetBytes(CRLF);
            //writer.append("Content-Type: application/octet-stream;").append(CRLF);
            rs.Write(buf, 0, buf.Length);
            rs.Flush();


            long bufferSize = Math.Min(bytesAvailable, maxBufferSize);
            buffer = new byte[bufferSize];
            while ((read = fs.Read(buffer, 0, buffer.Length)) != 0)
            {
                rs.Write(buffer, 0, read);
            }
            buf = Encoding.UTF8.GetBytes(CRLF);                
            rs.Write(buf, 0, buf.Length);
            rs.Flush();


            // End of multipart/form-data.
            buffer = Encoding.UTF8.GetBytes("--" + boundary + "--" + CRLF);
            rs.Write(buffer, 0, buffer.Length);

            using (var response = request.GetResponse())
            using (var responseStream = response.GetResponseStream())
            using (var reader = new StreamReader(responseStream))
            {

                result = reader.ReadToEnd();
            }
        }
        catch (Exception e)
        {
            result = e.InnerException != null ? e.InnerException.Message : e.Message;  
        }

        return result;
    }