本鱼拟成立工作室承接项目开发/软件定制/云设施开发运维/办公设备技术支持等,如您有相关需求,欢迎来询 | ::博客文章推荐::

一切浪费我时间的,都是我的敌人

: DOT.NET 木魚 12℃ 0评论

所以必须拉出来示众

上周我因为要调用微信开放平台的接口,很狠被微信摆了一道,特别生气,必须来吐槽,不然我这消化是好不了的,这世界膈应我的千千万,微信开放平台你算哪根葱。

事件是这样的,用的是 asp.net core 10.0,要调用的接口是微信开放平台的获得加密scheme码的接口。

为了便于演示,这里将部分代码摘录如下。

public record GenerateSchemeResponse(int errcode, string errmsg, string openlink);

app.MapGet(
    "/generateScheme",
    async () =>
    {
        var client = new HttpClient();
        var response = await client.PostAsJsonAsync(
            "https://api.weixin.qq.com/wxa/generatescheme?access_token=access_token",
            new
            {
                is_expire = false,
                expire_type = (int?)null,
                expire_interval = (int?)null,
                expire_time = (long?)null,
                jump_wxa = new
                {
                    path = "",
                    query = "",
                    env_version = "release"
                }
            });
        response.EnsureSuccessStatusCode();
        
        var msg = await response.Content.ReadFromJsonAsync<GenerateSchemeResponse>();

        return msg;
    })
.WithName("generateScheme");

呐,你别管这access_token的值为啥就是access_token,这就是个例子晓得伐,实际代码里不是这样。

来,Run it。

System.Net.Http.HttpRequestException: Response status code does not indicate success: 412 (Precondition Failed).
   at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
   at Program.<>c.<<<Main>$>b__0_0>d.MoveNext() in *********\WebApplication1\Program.cs:line 35
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.<ExecuteTaskOfT>g__ExecuteAwaited|134_0[T](Task`1 task, HttpContext httpContext, JsonTypeInfo`1 jsonTypeInfo)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

如你所见,必须报错。错误码是412,这是个HTTP错误代码。

那么这个错误代表什么意思呢?不知道。小程序的文档页面里,有一堆错误码列表,但是所有的错误码列表里,就是没有告诉你412错误代码是啥意思的。

并且,如果你抓包的话,你会发现,这个错误的响应极其简单清晰,可以说什么信息都没有。

通常来说,对于API接口的响应异常,我通常会立刻开始反思,是不是自己哪里搞错了。

放到这个例子里,我首先就开始怀疑,是不是参数错了。比如这个AK是不是搞错了?没编码?难道请求参数里的数据没有的话不能用null而是得忽略?

于是我在这里折腾了半个小时,各种换参数,编码,解码,期间还查了百度、逛了CSDN和掘金,并没有什么收获,但是所得到的响应永远是个雷打不动的412,且没有任何其它信息,查到的资料千篇一律,并没有提到这个412错误代码为何方神圣。

把这个请求的所有数据原封不动的复制到Postman中,突然发现Postman可以得到正确的响应:不管如何,起码人家不是412错误代码。

那么事情便很简单了不是,一定是这请求出了问题。

对比了一下Postman和程序的请求,第一感觉是,是不是User-Agent丢失导致的。历史上看到过一些WAF把这个头的缺失当做异常请求来进行拦截。

这个头……倒也是好加。

client.DefaultRequestHeaders.Add("User-Agent", "PostmanRuntime/7.51.0");

好加的东西不一定好用,涛声依旧了。

那……是Accept头导致的问题?……哦……不是。

那……总不会是Cache-Control头导致的问题吧?……哦……也不是。

那是……ConnectionAccept-Encoding导致的问题?……嗐……还不是。

删来删去,删掉Transfer-Encoding的时候,突然发现,412失踪了,取而代之的是说AK过期。

嗯??因为Transfer-Encoding: chunked编码导致的问题?……这他喵的不是RFC规范里的吗??

最初定义于 RFC 2616(HTTP/1.1 早期标准,1999 年发布),在 3.6.1 节规定 chunked 传输编码,14.41 节定义 Transfer-Encoding 头字段中的 chunked 取值,要求所有 HTTP/1.1 接收端必须支持该编码。

果然还得是你腾讯,狂到没边。

但话又说回来,这里为什么会有chunked编码?

目光重新转回 PostAsJsonAsync函数,这才发现它并不是HttpClient的标准方法,而是asp.net core中扩展出来的一个方法。我们来看一下这个方法的实现。

它最终生成了一个JsonContent对象并作为请求主体。那么我们再看一下这个对象的内部是怎么工作的。

 

呐,计算长度的时候直接返回了0,因此请求发出的时候并不知道内容多长,因此也就必须采用分块编码(chunked)。

那如果我们想要避免怎么办呢?那倒也好办。

await client.PostAsync(
    "https://api.weixin.qq.com/wxa/generatescheme?access_token=access_token",
    new StringContent(JsonSerializer.Serialize(
        new
        {
            is_expire = false,
            expire_type = (int?)null,
            expire_interval = (int?)null,
            expire_time = (long?)null,
            jump_wxa = new
            {
                path = "",
                query = "",
                env_version = "release"
            }
        }))
)

为啥我要这样多此一举呢?那还不是因为腾讯狂嘛。

 

腾讯:你的一小时,我要定了,你看是玩王者荣耀还是伺候微信开放平台,你自己选吧。

喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址