开门见山地说一下问题的原因:调用 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("\r\n--" + boundary + "\r\n");

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

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

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

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

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

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

继续仔细对比抓包,发现 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();

.NET Core HttpClient调用腾讯云对象存储Web API的"ERROR_CGI_PARAM_NO_SUCH_OP"问题的更多相关文章

  1. php 腾讯云 对象存储V5版本 获取返回的上传文件的链接方法

    腾讯云 对象存储V5版本 文档地址:https://github.com/tencentyun/cos-php-sdk-v5 调用简单文件上传方法: 返回数据如下 Array ( [data:prot ...

  2. Laravel项目使用腾讯云对象存储上传图片(cos-php-sdk-v5版本)

    为了加快网站访问速度.降低网站负载,现在越来越多的网站选择把图片等静态文件放在云上,这里介绍一下腾讯云对象存储在Laravel项目中的使用 1.申请腾讯云对象存储.创建Bucket.获取APPID等参 ...

  3. 微信小程序基于腾讯云对象存储的图片上传

    在使用腾讯云对象存储之前,公司一直使用的是传统的FTP的上传模式,而随着用户量的不断增加,FTP所暴露出来的问题也越来越多,1.传输效率低,上传速度慢.2.时常有上传其他文件来攻击服务器,安全上得不到 ...

  4. Docsify+腾讯云对象存储 COS,一键搭建云上静态博客

    最近一直在想如何利用 COS 简化静态博客的搭建过程.搜了很多的静态博客搭建过程,发现大部分的静态博客都要通过编译才能生成静态页面.功夫不负有心人,终于让我找到了一个超简洁博客的搭建方法. 效果预览 ...

  5. 腾讯云--对象存储cos绑定自定义域名

    1.登录腾讯云控制台,找到对象存储一栏 2.选择一个你想绑定域名的存储桶 3.进入你选择的存储桶,点击域名管理 4.选择自定义源站域名.在域名处填写你要设置的自定义域名,在源站类型处选择静态网站源站, ...

  6. 腾讯云对象存储COS新品发布——智能分层存储,自动优化您的存储成本

    近日,腾讯云正式发布对象存储新品--智能分层存储,能够根据用户数据的访问模式,自动地转换数据的冷热层级,为用户提供与标准存储一致的低延迟和高吞吐的产品体验,同时具有更低的存储成本. 熟悉数据存储的用户 ...

  7. Python调用腾讯云API,实现人脸年龄变化

    网上看到了一个教程,调用腾讯云的人脸识别api和修改年龄api来实现模拟人物不同年龄的面貌 但是大多数教程的代码都是想同的,估计是抄袭哪个人的关键是执行不了 刚好周杰伦马上要发新专辑了,小改一下,拿杰 ...

  8. 谈谈调用腾讯云【OCR-通用印刷体识别】Api踩的坑

    一.写在前面 最近做项目需要用到识别图片中文字的功能,本来用的Tesseract这个写的,不过效果不是很理想. 随后上网搜了一下OCR接口,就准备使用腾讯云.百度的OCR接口试一下效果.不过这个腾讯云 ...

  9. C# 调用腾讯云接口获取视频基本信息

    做项目需要上传视频,获取时长,上传教程很多,获取信息很少,官方只有一条请求地址. 找了好久,都没有说这个请求地址怎么用.最后发现需要调用腾讯云SDK 官方地址:https://github.com/Q ...

随机推荐

  1. Windows10 IIS配置PHP运行环境

    http://www.cnblogs.com/wenhainan/p/5600346.html 在Windows 8 的IIS(8.0)中搭建PHP运行环境: 一:安装IIS服务器 1.进入控制面板& ...

  2. Oracle11g登录名和密码不区分大小写

    问题描述: oracle11g对账户密码实行大小写识别,烦的一比!想移除此限制 问题解决: oracle 11g以前的版本的用户名和密码是不区分大小写!oracle 11g 用户名和密码默认区分大小写 ...

  3. 美化你的GRUB,全面支持中文(菜单、提示、帮助)适用7.04-9.04

    本文根据网络资料整理而成,在此鸣谢各位作者. 本方法适合 7.04-9.04版本,9.10使用了grub2,请看这里. http://forum.ubuntu.org.cn/viewtopic.php ...

  4. Qt下多线程日之类

    刚google到了,晚上回去试一下! 代码地址 https://gitorious.org/cutelogger/cutelogger/source/e3c2745c6c5f38896f87472e0 ...

  5. [Aaronyang] 写给自己的WPF4.5 笔记10[层次数据需求处理,TreeView绿色文章1/4]

     我的文章一定要做到对读者负责,否则就是失败的文章  ---------   www.ayjs.net    aaronyang技术分享 AY留言: 文章根据难易,我根据游戏的规则进行了分色,希望读者 ...

  6. HTML5 完美解决javascript中iphone手机和android手机复制文本到剪切板问题

    1.执行以下解决方案条件:(这个是原理) ①执行复制方法时 所复制文字不能被任何 块级元素和行内块元素和行内元素遮盖否则无效:(解决方案:将文本通过绝对定位或其他方式移除屏幕外) ②ios中不能复制属 ...

  7. Android Studio updating indices 一直刷新和闪烁

    Android Studio 更新到了 3.1.3 版本,在导入了工程以后,一直出现了 updating indices 刷新的情况,造成闪烁,在切换到其他视图以后,Android Studio 会一 ...

  8. [docker]使用quaaga实现(rip ospf)实现主机间容器互通

    使用quaaga实现(rip ospf)实现主机间容器互通 - n1设置 brctl addbr br0 ip a a 10.1.1.1/24 br0 ip a a 10.1.1.1/24 dev b ...

  9. 【spark 深入学习 05】RDD编程之旅基础篇-01

    ---------------- 本节内容 1.RDD的工作流程 2.WordCount解说  · shell版本WordCount  · java版本WordCount -------------- ...

  10. Extjs4 DateTimeField,日期时间控件完美版

    网上若干类似的控件,要么是有bug,要么是操作体验不合理,这里贡献一个比较科学的版本. 扩展包下载: http://files.cnblogs.com/qidian10/Ext.ux.rar 解压至E ...