You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#.Net不添加服务引用调用asmx服务遇403禁止错误排查

问题

我正在实现无需添加服务引用即可调用asmx WebService方法的功能,该asmx未提供WSDL。通过Fiddler和Postman均可正常访问该服务,但使用C#代码调用时却抛出403禁止异常。使用环境为VS2022控制台应用(.Net Framework 4.6.2)。

我的C#代码如下:

internal class Class3
{
    string _soapEnvelope =
    @"<soap:Envelope
        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns:xsd='http://www.w3.org/2001/XMLSchema'
        xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
    <soap:Body></soap:Body></soap:Envelope>";

    private string CreateSoapEnvelope()
    {
        Dictionary<string, string> Params = new Dictionary<string, string>();
        Params.Add("aId", "11"); // Add parameterName & Value to dictionary
        Params.Add("cId", "22");
        Params.Add("lId", "20");
        string MethodCall = "<" + "GetSettings" + @" xmlns=""http://tempuri.org/"">";
        string StrParameters = string.Empty;
        foreach (var param in Params)
        {
            StrParameters += string.Format("<{0}>{1}</{0}>", param.Key, param.Value);
        }
        MethodCall = MethodCall + StrParameters + "</" + "GetSettings" + ">";
        StringBuilder sb = new StringBuilder(_soapEnvelope);
        sb.Insert(sb.ToString().IndexOf("&lt;/soap:Body&gt;"), MethodCall);
        return sb.ToString();
    }

    private HttpWebRequest CreateWebRequest()
    {
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("sample.asmx");
        webRequest.Headers.Add("SOAPAction", "\"http://tempuri.org/" + "GetSettings" + "\"");
        webRequest.Headers.Add("To", "sample.asmx");
        webRequest.Credentials = CredentialCache.DefaultCredentials;
        webRequest.ContentType = "application/x-www-form-urlencoded";
        webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9";
        webRequest.Host = "sample.com";
        webRequest.Headers.Set(HttpRequestHeader.CacheControl, "max-age=0");
        webRequest.Headers.Add("Upgrade-Insecure-Requests: 1");
        webRequest.Headers.Add("Origin", "null");
        webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
        webRequest.Headers.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6");
        webRequest.Method = "POST";
        return webRequest;

    }

    public string InvokeService()
    {
        try
        {
            WebResponse response = null;
            string strResponse = "";
            //Create the request
            HttpWebRequest req = this.CreateWebRequest();
            //write the soap envelope to request stream
            using (Stream stm = req.GetRequestStream())
            {
                using (StreamWriter stmw = new StreamWriter(stm))
                {
                    stmw.Write(this.CreateSoapEnvelope());
                }
            }
            //get the response from the web service
            response = req.GetResponse();
            Stream str = response.GetResponseStream();
            StreamReader sr = new StreamReader(str);
            strResponse = sr.ReadToEnd();
            return HttpUtility.HtmlDecode(strResponse);
        }
        catch (Exception ex)
        {
            return "";
        }
    }
}

internal class Program
{
    static void Main(string[] args)
    {   
        new Class3().InvokeService();
    }
}

尝试添加以下请求头后问题仍未解决:

webRequest.ContentLength = 600000;
webRequest.ProtocolVersion = HttpVersion.Version11;
webRequest.KeepAlive = false; 
webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36";
排查与解决方案

以下是代码中存在的核心问题及修正方案:

1. ContentType 错误

ASMX SOAP请求的ContentType必须为 text/xml; charset=utf-8(SOAP 1.1)或application/soap+xml; charset=utf-8(SOAP 1.2),你当前设置的application/x-www-form-urlencoded是表单提交类型,服务端无法识别SOAP XML结构,这是导致403的核心原因之一。

修正:

webRequest.ContentType = "text/xml; charset=utf-8";

2. SOAP信封转义错误

你的_soapEnvelope中使用了&lt;和&gt;转义标签,但直接写入请求流时应该使用原始XML标签,转义后的内容会被服务端当作纯文本而非XML结构,导致SOAP格式无效。

修正:

string _soapEnvelope =
@"<soap:Envelope
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    xmlns:xsd='http://www.w3.org/2001/XMLSchema'
    xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
<soap:Body></soap:Body></soap:Envelope>";

同时修正CreateSoapEnvelope中的插入位置:

sb.Insert(sb.ToString().IndexOf("</soap:Body>"), MethodCall);

3. 不必要的请求头干扰

移除服务端不需要的请求头,避免触发校验逻辑:

  • 移除Upgrade-Insecure-Requests: 1:该头用于HTTP升级HTTPS,SOAP服务无需此设置
  • 移除Origin: null:控制台应用通常不需要设置Origin,若Postman中没有该头则直接删除;若服务端要求Origin,应设置为Postman中使用的有效值
  • 简化Accept头:仅保留服务端支持的类型,比如application/xml, text/xml

4. ContentLength设置错误

硬编码ContentLength = 600000会导致请求内容长度与实际不符,服务端可能拒绝请求。应计算SOAP信封的实际字节长度:

string soapContent = this.CreateSoapEnvelope();
byte[] contentBytes = Encoding.UTF8.GetBytes(soapContent);
webRequest.ContentLength = contentBytes.Length;

// 写入流时改用字节数组,避免编码问题
using (Stream stm = req.GetRequestStream())
{
    stm.Write(contentBytes, 0, contentBytes.Length);
}

5. 请求URL完整性

确保WebRequest.Create的参数是完整的HTTP/HTTPS URL,比如https://sample.com/sample.asmx,而非仅sample.asmx。

6. SOAPAction格式校验

确认SOAPAction的值与Postman中使用的完全一致,注意引号和路径是否正确,比如"http://tempuri.org/GetSettings"是否符合服务端要求。

修正后的完整CreateWebRequest方法示例

private HttpWebRequest CreateWebRequest()
{
    // 替换为完整的服务URL
    HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://sample.com/sample.asmx");
    webRequest.Headers.Add("SOAPAction", "\"http://tempuri.org/GetSettings\"");
    webRequest.Credentials = CredentialCache.DefaultCredentials;
    // 正确设置SOAP ContentType
    webRequest.ContentType = "text/xml; charset=utf-8";
    // 简化Accept头
    webRequest.Accept = "application/xml, text/xml";
    webRequest.Host = "sample.com";
    webRequest.Headers.Add("Accept-Encoding", "gzip, deflate");
    webRequest.Headers.Add("Accept-Language", "en-US,en;q=0.9,zh-CN;q=0.8,zh-TW;q=0.7,zh;q=0.6");
    // 添加UserAgent匹配Postman
    webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36";
    webRequest.Method = "POST";
    webRequest.ProtocolVersion = HttpVersion.Version11;
    return webRequest;
}

额外建议

  • 用Fiddler捕获Postman的请求和你的代码请求,对比两者的所有请求头、请求体,找出差异点
  • 在catch块中捕获具体的WebException,获取服务端返回的详细错误信息,比如:
catch (WebException ex)
{
    if (ex.Response is HttpWebResponse response)
    {
        using (var reader = new StreamReader(response.GetResponseStream()))
        {
            string error = reader.ReadToEnd();
            // 输出错误信息用于排查
            Console.WriteLine(error);
        }
    }
    return "";
}

内容的提问来源于stack exchange,提问作者Abhijit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:16:07