zoukankan      html  css  js  c++  java
  • .NET Core HttpClient调用腾讯云对象存储Web API的"ERROR_CGI_PARAM_NO_SUCH_OP"问题

    开门见山地说一下问题的原因:调用 web api 时请求头中多了双引号,请求体中少了双引号。

    腾讯云提供的对象存储(COS)C# SDK 是基于 .NET Framework 用 WebRequest 实现的,我们直接将这个实现迁移到 .NET Core 是可以正常调用,但后来我们基于 HttpClient 实现,调用 web api 时总是返回 "ERROR_CGI_PARAM_NO_SUCH_OP" 错误。

    用 Wireshark 抓包后发现,基于 WebRequest 的实现的请求包开头比基于 HttpClient 的实现多了个 "Preamble: 0d0a"。

    1)基于 WebRequest 的实现

    2)基于 HttpClient 的实现

    检查代码后发现,在构建 multipart/form-data 时,腾讯云官方基于 WebRequest 的实现是这样构建数据包的开头的:

    var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
    var beginBoundary = Encoding.ASCII.GetBytes("
    --" + boundary + "
    ");

    我们基于 HttpClient 的实现用的是 MultipartFormDataContent :

    var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
    var data = new MultipartFormDataContent(boundary);

    前者构建的 Multipart 数据包比后者多出了 (回车换行),而 0d0a 正是 的 ASCII 码。根据 Multipart Content-Type 规范,这个多出来的 是多余的,所以被解析为  "Preamble: 0d0a" 。

    于是修改基于 HttpClient 的实现,也加上这个额外的 :

    var ms = new MemoryStream();
    var bytes = Encoding.UTF8.GetBytes("
    ");
    ms.Write(bytes, 0, bytes.Length);
    (await data.ReadAsStreamAsync()).CopyTo(ms);
    ms.Position = 0;
    var sc = new StreamContent(ms);
    sc.Headers.ContentType = data.Headers.ContentType;
    request.Content = sc;

    但加上后依然是"ERROR_CGI_PARAM_NO_SUCH_OP"错误(实际上不加开头的 也没关系,问题与这个无关)。

    继续仔细对比抓包,发现 HttpClient 的实现中 form-data 部署少了双引号,比如 name=op ,基于 WebRequest 的实现用的是 name="op"

    但加上后依旧是"ERROR_CGI_PARAM_NO_SUCH_OP"错误。

    再继续对比抓包,发现 HttpClient 的实现这 Content-Type 中比 WebRequest 的实现多了2个双引号

    1) Content-Type: multipart/form-data; boundary="---------------8d5289300ea3a0d"  

    2)  Content-Type: multipart/form-data; boundary=---------------8d527aeed341201 

    去找这2个双引号之后,问题终于解决了。

    最终基于 .NET Core HttpClient 的实现代码如下("Preamble: 0d0a"没有影响,不需要加):

    var request = new HttpRequestMessage(HttpMethod.Post, url);
    request.Headers.Authorization = new AuthenticationHeaderValue("Authorization", signature);
    
    var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
    var data = new MultipartFormDataContent(boundary);
    data.Add(new ByteArrayContent(Encoding.UTF8.GetBytes("upload")), ""op"");
    
    var streamContent = new StreamContent(uploadStream);
    streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
    {
        Name = ""fileContent"",
        FileName = """ + fileName + """
    };
    streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    data.Add(streamContent);
    
    data.Headers.Remove("Content-Type");
    data.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
    request.Content = data;
    var response = await _httpClient.SendAsync(request);
    var json = await response.Content.ReadAsStringAsync();
  • 相关阅读:
    OC学习一周总结
    C语言基础学习总结
    123
    汇编中中括号[]作用以及lea和mov指令的区别
    C#获取局域网内所有的SQL Server服务器名
    .net 初中级程序员招聘
    C#在客户端与 JS 交互
    [ZT]Mac下安装mysql和workbench
    Eclipse文件夹导入Jar
    Tomcat配置后提示404的解决办法
  • 原文地址:https://www.cnblogs.com/dudu/p/7811797.html
Copyright © 2011-2022 走看看