Postman可以正常发出HTTP请求,但是C#代码却无法成功。

12

我想在C#中进行简单的HTTP请求,但是某些东西不能正常工作,我得到的只是403 Forbidden状态码。

当我尝试在Postman中进行相同的请求时,一切都很顺利。 我尝试运行Fiddler并查看由Postman发送的所有标头。 我复制粘贴了它们所有的标头,但是在由C#代码发送的请求中仍然得到了403 Forbidden

C#代码(使用https://flurl.dev):

public static void Main(string[] args)
{
    FlurlHttp.Configure(settings => {
        settings.HttpClientFactory = new MyClientFactory();
    });

    var url = "https://example.com"
        .AppendPathSegments(new[] { "v1", "oauth", "accesstoken" })
        .SetQueryParam("grant_type", "client_credentials")
        .AllowAnyHttpStatus()
        .WithBasicAuth("username", "password")
        .WithHeaders(new {
            User_Agent = "Something/0.4.0 Dalvik/2.1.0 (Linux; U; Android 5.1.1; SM-G975F Build/NRD90M)",
            X_Secret_Header = "secret_encoded_value",
            accept_encoding = "gzip, deflate",
            Accept = "*/*"
        });

    HttpResponseMessage msg = url.GetAsync().Result;

    Console.WriteLine("StatusCodeString: " + msg.StatusCode.ToString());
    Console.WriteLine();
    Console.WriteLine(msg.Content.ReadAsStringAsync().Result);
}

class MyClientFactory : DefaultHttpClientFactory
{
    public override HttpMessageHandler CreateMessageHandler()
    {
        return new HttpClientHandler
        {
            AllowAutoRedirect = false
        };
    }
}

C# 请求和响应:

CSharp Request in Fiddler CSharp Response

Postman 请求和响应:

Postman Headers Postman Response Postman Response in Fiddler

有人能解释一下为什么这不起作用吗?头部、其他内容都是相同的。

我将URL替换为“example.com”,因为我不想在这里显示真实API URL。

还有很抱歉放了这么多图片..我不知道别的方式如何展示问题。


1
Don't post images of text. - RalfFriedl
3
你尝试过使用 C# 的 HttpClient 吗?它能产生相同的结果吗? - Tobias Tengler
2
403错误是否可能来自代理服务器? - John Wu
3
是的,我尝试使用HttpClient并得到了相同的结果。 - modugnico
2
@JohnWu 当我使用Fiddler运行请求时,Postman和C#都返回403。但是没有Fiddler时,Postman可以工作,但C#不能。 - modugnico
2
@Hartes 你曾经为这个问题找到解决方案吗? - Giorgos Betsos
8个回答

16

从Postman中,右侧应该有一个名为“代码”的链接。点击它,然后选择C#以获取由Postman生成的代码。将其粘贴并尝试使用。


Postman生成的代码在.NET Framework应用程序中无法正常工作,当您明确设置Cookie头时。要发送cookie,您需要在HttpClient构造函数中指定处理程序,并且可以使用UseCookies = false与手动设置Cookie头,或者使用CookieContainer来代替。 - Rudey

7

对我来说问题在于C#中的TLS设置。尝试在您的应用程序开头或HTTP请求代码之前添加此行:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

3
谢谢!这对我有用!但是,为什么更改到这个特定的协议会起作用呢? - user1294510
1
这对我也起作用了。不错的东西! - Vinnie Amir

5

为了帮助搜索相关问题的人们,这种错误可能有多种原因。

以下是帮助调试此类问题的步骤:

  1. 下载Fiddler(或类似工具如Wireshark)以记录网络流量。
  2. 通过postman进行正常请求(记录流量)
  3. 通过C#进行失败请求(记录流量)
  4. 查看两个请求之间的不同之处。

在我的情况下,我的身份验证中出现了引号。这是一个微妙的区别,我直到比较两者才意识到。

正常调用(200 OK)

使用Fiddler查看的正常调用

失败调用(401未经授权)

使用Fiddler查看的失败调用


4

我遇到了类似的问题,这里的所有答案都没有起作用。在我的 C# 客户端中,我得到了一个 403 的错误,但在 Postman 中它却运行良好。经过几个小时的尝试,并遵循 @JsAndDotNet 的建议使用 Fiddler,我发现服务器在没有 User-Agent 的情况下会弹回所有请求。

确保的一种方法是检查响应。在我的情况下,响应应该是 json 格式的,但我得到的是 text/html,这表明服务器将我的请求视为来自浏览器并因此阻止了它。

指定我的自定义 User-Agent(任意随机字符串)解决了这个问题。


我遇到了一个异常,提示“接收到无效的头部名称:'<!--'。”,但这个请求在Postman中是可以工作的。添加用户代理名称解决了这个问题。 <3 - Culme
非常感谢你,你救了我,我遇到了完全相同的问题,尝试了其他所有方法都没有起作用。 - undefined

3

虽然这篇文章已经过时了,但是为了得到与Postman发送的相同的C#代码,请让Postman为您生成代码。不过首先您必须从nuget或PM控制台获取RestSharp库,输入以下内容:

Install-Package RestRequest -Version 1.2.0

步骤:

1- 从Postman调用您的REST API

2- 点击代码按钮 enter image description here 3- 弹出窗口将会打开,然后选择您想要的任何语言,对于您的情况是C# enter image description here


谢谢你,Mostafa - 这是唯一让我成功的解决方案。 - creater

2
我的建议是从Postman和C#应用程序中检索原始请求字符串,然后使用类似https://text-compare.com/的工具查找差异。猜测可能存在一些极其微小的差异,例如额外的斜杠,这很难用肉眼察觉。

1
我使用您提供的网站比较了请求字符串,但结果显示:“这两个文本是相同的”。 - modugnico

1
下一步是将您的C#代码和Postman中的原始请求和响应进行对比,将它们并排放置并比较差异-我向您保证至少会有一个差异。 :-) 403授权问题,因此令牌将是第一个嫌疑对象,因为请求的错误结构更可能引发400“错误请求”错误。
在这种特殊情况下,我已经在我的机器上使用Flurl在VS2019中运行了您的代码,并且似乎工作正常。 它返回一个示例HTML页面:
<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
    body {
        background-color: #f0f0f2;
        margin: 0;
        padding: 0;
        font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;

    }
    div {
        width: 600px;
        margin: 5em auto;
        padding: 50px;
        background-color: #fff;
        border-radius: 1em;
    }
    a:link, a:visited {
        color: #38488f;
        text-decoration: none;
    }
    @media (max-width: 700px) {
        body {
            background-color: #fff;
        }
        div {
            width: auto;
            margin: 0 auto;
            border-radius: 0;
            padding: 1em;
        }
    }
    </style>
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is established to be used for illustrative examples in documents. You may use this
    domain in examples without prior coordination or asking for permission.</p>
    <p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>

1
我用“example.com”替换了实际的URL,因为我不想在这里显示真正的API。 - modugnico
1
好的,你的代码可以运行了。现在打开Postman中的“Authorization”选项卡,检查你正在使用的令牌是否与你在VS Code中拥有的相同。 - Duck Ling

1
如果有人遇到同样的问题,希望这篇文章能帮到你。我曾经遇到过同样的问题,我在调用API时遇到了麻烦,因为postman和visual studio之间的所有内容,包括授权头部都是完全相同的。但是当我仔细观察Fiddler时,我注意到当使用Postman时,被调用的API是https://api.someplace.com/properties/?pagesize=20,而在Visual Studio中我使用的是https://api.someplace.com/properties?pagesize=20
请注意,在“属性”和查询字符串之间缺少斜杠。“......properties/?......”可以正常工作,“......properties?......”会导致403错误。
我认为(如果我错了,请纠正我),实际发生的事情是在第一个HTTP调用中,斜杠丢失了,服务器对API进行了HTTP 301重定向。当重定向发生时,授权头没有随之传递,从而导致了403授权错误。
现在我不知道为什么需要这个重定向,我构建的任何API都允许这两种情况,不需要重定向。但最终,我只需将URL更改为“../properties/?etc...”,问题就解决了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接