Web Service 和 Web API

Web Service 严格遵循 SOAP 协议,像一套严谨的"外交文书"系统,通过 XML 信封(SOAP Envelope)和 WSDL 契约书来确保跨语言、跨平台的绝对兼容性,但笨重缓慢;而 Web API 本质上是现代 HTTP 应用的"快递服务",利用 GET/POST 等标准 HTTP 方法直接传输 JSON 数据,追求轻量、快速,是移动互联网时代前后端交互的主流

维度 Web Service (SOAP) Web API (RESTful HTTP)
💡 含义本质 基于SOAP协议的远程过程调用技术,将业务功能封装为服务端点。 基于HTTP协议的接口架构风格,将数据视为资源,通过URL暴露。
📦 数据格式 仅限XML。需封装在复杂的SOAP Envelope中。 首选JSON,也可支持XML/纯文本。体积小,解析快。
📜 契约描述 强制要求WSDL文件。客户端必须通过WSDL生成代理类才能调用,相当于"硬合同"。 无强制契约。通常通过Swagger/OpenAPI等文档工具描述,相当于"说明书"。
📮 调用方式 通过SOAP信封调用 。只能使用POST,请求体是特定XML结构,Header必须设置text/xml 直接HTTP调用。充分利用GET/POST/PUT/DELETE,URL即资源路径,Body传JSON。
🎯 典型场景 企业内部系统集成。如对接SAP、银行支付接口,或跨Java/.NET/Php老旧系统交互。 互联网公开服务。如手机App后端、Vue/React单页应用、第三方开放平台(微信/支付宝API)。

Web Service 调用:严格遵循契约的"重武器"

Web Service 的调用过程比较固定,核心是"获取WSDL -> 生成客户端 -> 填充SOAP报文"。

原始HTTP报文(用于Postman调试)

直接在工具中调用 Web Service 必须构造如下SOAP信封。请求头必须指定 Content-Type: text/xml;charset=utf-8,Body是特定的XML结构

cs 复制代码
POST /calculator HTTP/1.1
Content-Type: text/xml;charset=utf-8

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:cal="http://service.example.com/">
   <soapenv:Header/>
   <soapenv:Body>
      <cal:add>
         <a>5</a>
         <b>3</b>
      </cal:add>
   </soapenv:Body>
</soapenv:Envelope>
cs 复制代码
public async Task<InvokeDto> Invoke(InvokeFilter invoke)
{
    InvokeDto invokeDto = new InvokeDto();
    XmlDocument xx = new XmlDocument();
    HttpHelper helper = new HttpHelper();
    string url = _configuration.GetSection("Interface")["Invoke"];
    var Token = await GetToken();//获取Token值
    option option = new option();
    if (Token != null && Token.status == "200")
    {
        option.key = Token.key;
        option.value = Token.value;
    }

    var client = _httpClientFactory.CreateClient("Client1");
    string strJson = $"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:v1=\"http://interface.hzero.org/v1/\">" +
        $"<soapenv:Header/><soapenv:Body><v1:invoke><namespace>{invoke.name}</namespace>" +
        $"<serverCode>{invoke.serverCode}</serverCode><interfaceCode>{invoke.interfaceCode}</interfaceCode>" +
        $"<payload><headerParamMap>{invoke.headerParamMap}</headerParamMap><pathVariableMap>{invoke.pathVariableMap}</pathVariableMap>" +
        $"<requestParamMap>{invoke.requestParamMap}</requestParamMap><bodyParamMap>{invoke.bodyParamMap}</bodyParamMap>" +
        $"<mediaType>{invoke.mediaType}</mediaType><payload>{invoke.payload}</payload><retrySourceBatchNum>{invoke.retrySourceBatchNum}</retrySourceBatchNum></payload>" +
        $"</v1:invoke></soapenv:Body></soapenv:Envelope>";
    string res = await helper.HttpRequest(client, "POST", "text/xml", url, strJson, option);
    xx.LoadXml(res);//加载xml
    if (xx != null)
    {
        invokeDto.status = xx.GetElementsByTagName("status")[0].InnerText;
        invokeDto.batchNum = xx.GetElementsByTagName("batchNum")[0].InnerText;
        invokeDto.invokeKey = xx.GetElementsByTagName("invokeKey")[0].InnerText;
        invokeDto.message = xx.GetElementsByTagName("message")[0].InnerText;
        invokeDto.targetResponseHeaders = xx.GetElementsByTagName("targetResponseHeaders")[0].InnerText;
        invokeDto.payload = xx.GetElementsByTagName("payload")[0].InnerText;
        if (!invokeDto.payload.IsNullOrEmpty())
        {
            invokeDto.payloadDto = JsonConvert.DeserializeObject<payload>(invokeDto.payload);
        }
    }
    return await Task.FromResult(invokeDto);
}
cs 复制代码
                InvokeFilter invokeFilter = new()
                {
                    name = "AA",
                    serverCode = "code",
                    interfaceCode = interfaceCode,
                    payload = JsonConvert.SerializeObject(inputDto)
                };
                var invokeDto = await Invoke(invokeFilter);
                // 对返回的参数做处理
                if (invokeDto.status == "200")//接口交互成功
cs 复制代码
        public async Task<string> InvokeWms(InvokeFilter invoke)
        {
            XmlDocument xx = new XmlDocument();
            //判断接口信息是否存在
            SysParameter sysParameter = await _sysParameterRepository.FirstOrDefaultAsync(x => x.ParCode == "XXXApiInterface");
            if (sysParameter == null)
            {
                throw new BusinessException(code: "10000", message: $"未在系统参数中配置XXX接口的地址");
            }
            var client = _httpClientFactory.CreateClient("Client1");
            string strJson = $"<soap-env:Envelope xmlns:soap-env=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
               $"<soap-env:Header/><soap-env:Body>" +
               $"<urn:{invoke.interfaceCode} xmlns:urn=\"http://cxf.knowwikibackend.ath.cn/\">" +
               $"<urn:INPUT>{invoke.payload}" +
               $"</urn:INPUT>" +
               $"</urn:{invoke.interfaceCode}>" +
               $"</soap-env:Body></soap-env:Envelope>";


            string res = await HttpHelper.HttpRequestAsync(client, "POST", "text/xml", sysParameter.ParValue, strJson, null, null);
            xx.LoadXml(res);//加载xml
            if (xx != null)
            {
                //var outJson = xx.GetElementsByTagName("Header")[0].InnerText;
                string outJson = xx.SelectSingleNode("//return").InnerText;
                return outJson;
            }
            return null;
        }

Web API 调用:灵活通用的"轻骑兵"

Web API 的调用非常直观,任何支持HTTP的语言或工具都可以直接调用。

🔧 如何使用(JavaScript + Fetch)

这是现代前端调用后端接口的标准写法,无论是 Vue、React 还是原生 JS 都通用

cs 复制代码
using (HttpClient client = new HttpClient())
{
    // GET请求:查询数据 + OData过滤语法示例
    string requestUrl = "https://localhost:44319/api/odata/Employee?$filter=FirstName eq 'Mary'&$select=LastName,Email";
    string jsonResult = await client.GetStringAsync(requestUrl);
    // 输出:[{"LastName":"Tellitson","Email":"Mary_Tellitson@example.com"}]
    
    // POST请求:创建新资源
    var newEmployee = new { FirstName = "Mary", LastName = "Gordon" };
    string jsonBody = JsonSerializer.Serialize(newEmployee);
    var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
    
    var response = await client.PostAsync("https://localhost:44319/api/odata/Employee", content);
    // 状态码 201 Created 表示资源创建成功
}

使用(.NET HttpClient)

C# 后端调用其他 Web API 的典型写法

cs 复制代码
using (HttpClient client = new HttpClient())
{
    // GET请求:查询数据 + OData过滤语法示例
    string requestUrl = "https://localhost:44319/api/odata/Employee?$filter=FirstName eq 'Mary'&$select=LastName,Email";
    string jsonResult = await client.GetStringAsync(requestUrl);
    // 输出:[{"LastName":"Tellitson","Email":"Mary_Tellitson@example.com"}]
    
    // POST请求:创建新资源
    var newEmployee = new { FirstName = "Mary", LastName = "Gordon" };
    string jsonBody = JsonSerializer.Serialize(newEmployee);
    var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
    
    var response = await client.PostAsync("https://localhost:44319/api/odata/Employee", content);
    // 状态码 201 Created 表示资源创建成功
}
cs 复制代码
        public static async Task<string> PostAsync(string url, string postData)
        {
            string result = string.Empty;
            //设置Http的正文
            HttpContent httpContent = new StringContent(postData);
            //设置Http的内容标头
            httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
            //设置Http的内容标头的字符
            httpContent.Headers.ContentType.CharSet = "utf-8";
            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.Timeout = new System.TimeSpan(0, 0, 0, 240);
                //异步Post
                HttpResponseMessage response = await httpClient.PostAsync(url, httpContent);
                //输出Http响应状态码
                //statusCode = response.StatusCode.ToString();
                //确保Http响应成功
                result = await response.Content.ReadAsStringAsync();
                //if (response.IsSuccessStatusCode)
                //{
                //    //异步读取json
                //    result = await response.Content.ReadAsStringAsync();
                //}
            }
            return result;
        }
cs 复制代码
 string response = await HttpHelper.PostAsync(sysParameter.ParValue,            JsonConvert.SerializeObject(input));
 var responseInfo = JsonConvert.DeserializeObject<ErpCallResult>(response);
 if (responseInfo.Code == 1)
 {


 }

Web API 的跨平台/跨语言能力

Web API(RESTful HTTP)天生就是跨平台、跨语言的。 这不是一个附加功能,而是它的核心设计理念。

1. 跨语言:任何语言都能调用

2. 跨平台:任何操作系统都能运行

服务端:

  • 可以在 Windows 上用 C# 编写 Web API

  • 可以在 Linux 上用 Java/Go/Python 部署

  • 可以在 macOS 上用 Node.js 开发调试

  • 客户端根本不关心服务端是什么系统

客户端:

  • iOS App(Swift)调用 Web API

  • Android App(Kotlin/Java)调用 Web API

  • Windows 桌面程序(C#)调用 Web API

  • Linux 命令行工具(Python)调用 Web API

  • 智能电视、车载系统、物联网设备...

cs 复制代码
# Linux服务器上用curl测试API
curl https://api.weixin.qq.com/cgi-bin/token

# Windows上用PowerShell调用同一API
Invoke-RestMethod -Uri https://api.weixin.qq.com/cgi-bin/token

# 手机上用Shortcuts自动化工具调用
# 同样的URL,同样的参数

Web Service 也能跨平台,但大家更推崇 Web API

维度 Web Service (SOAP) Web API (REST)
跨平台/跨语言 ✅ 支持 ✅ 支持
调用复杂度 ❌ 高(需生成代理类) ✅ 低(直接HTTP)
调试难度 ❌ 需要SOAP专用工具 ✅ 浏览器/curl即可
移动端适配 ❌ 负载重,解析慢 ✅ 轻量,解析快
防火墙穿透 ❌ 通常被拦截 ✅ 标准80/443端口

本质区别:

Web Service 的跨语言 - 是强制性的

  • 你必须先用 WSDL 生成客户端代理代码

  • 你的代码必须遵循特定的 SOAP 协议结构

  • 双方必须严格契约同步

Web API 的跨语言 - 是自然性的

  • HTTP 是互联网的基础协议,任何语言都有 HTTP 客户端

  • JSON 是通用数据格式,任何语言都有 JSON 解析器

  • 不需要任何代码生成,直接拼 URL、发请求、拿结果

相关推荐
MaoziShan18 小时前
CMU Subword Modeling | 09 Lexemes, or What Dictionaries Know about Morphology
开发语言·人工智能·机器学习·语言模型·自然语言处理·c#
游乐码18 小时前
c#选择排序
c#·排序算法
listhi52020 小时前
基于C#实现动态人脸检测
开发语言·c#
rabbitlzx1 天前
《Async in C# 5.0》第十四章 深入探讨编译器对于async的转换
java·开发语言·c#·异步·asynchronous
智商偏低1 天前
unity 如何渲染大场景
c#
光泽雨1 天前
单例模式代码理解
开发语言·c#
软泡芙1 天前
【C#】一个原始的标准蓝牙心率血氧服务的数据:字节数组byte[]有5个数据分别的0、0、240、0、240,转成IEEE 11073 SFLOAT
c#
gc_22992 天前
C#学习调用OpenMcdf模块解析ole数据的基本用法(2)
c#·ole·openmcdf·offvis软件