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、发请求、拿结果