如何通过 Jquery 调用 C# WCF 服务修复 "ERR_ABORTED 400 (Bad Request)" 错误?
How to fix "ERR_ABORTED 400 (Bad Request)" error with Jquery call to C# WCF service?
我创建了一个简单的 C# WCF 服务,它 returns 一个带有 html 代码的字符串。当我在 WCF 解决方案中使用一个简单的 MVC 项目使用此服务时,everythigs 工作正常。
- 服务代码
public class ConnectorService : IConnectorService
{
public string GetData()
{
return "<a href='www.test.com.br'>test</a>";
}
}
- 接口代码
[ServiceContract]
public interface IConnectorService
{
[OperationContract]
string GetData();
}
此测试后,我在本地 IIS 中发布了此服务,并尝试使用 html 页面使用此服务,该页面不在 WCF 解决方案内,但位于服务的同一 IIS 目录内。
- HTML代码
<html>
<head>
<title>test</title>
<script src='Scripts/jquery-3.3.1.min.js'></script>
</head>
<body>
<div id='divContent'></div>
</body>
</html>
<script type='text/javascript'>
$(document).ready(function () {
$.ajax({
url: 'http://localhost/ConnectorService.svc/GetData',
contentType: 'application/json; charset=utf-8',
type: "GET",
dataType: 'jsonp',
success: function (data) {
$('#divContent').html(data);
},
error: function (error) {
alert("error: status - " + error.status + " | text: " + error.statusText);
}
});
});
</script>
当我在浏览器上打开这个 html 文件时,出现 2 个错误:
1) CORS 策略 - 我用 global.asax 文件修复了这个
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
2) 错误 400 - 错误请求
我尝试了几种堆栈溢出的解决方案,通常会更改我的 ajax 调用、global.asax 和 web.config 文件,但我总是在 chrome 控制台中收到错误的请求错误。
- web.config代码
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Headers" value="Content-Type,Accept" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
我认为这是一个有简单解决方案的简单问题,但是经过几天的测试,我觉得我在追自己的尾巴。有人可以为我提供解决方案吗?
提前致谢。
调用有问题。通常,我们通过使用客户端代理class而不是直接发送http请求来调用典型的WCF服务。
$.ajax({
url: 'http://localhost/ConnectorService.svc/GetData',
contentType: 'application/json; charset=utf-8',
type: "GET",
dataType: 'jsonp',
success: function (data) {
$('#divContent').html(data);
},
error: function (error) {
alert("error: status - " + error.status + " | text: " + error.statusText);
}
这种直接发送http请求调用服务的样式,一般适用于Restful样式的服务,请参考下面的link。
https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design
Asp.net WebAPI 和 WCF 都可以创建 Restful 风格的服务。
https://docs.microsoft.com/en-us/aspnet/web-api/
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-web-http-programming-model-overview
根据您的示例,我们可以将 WCF 服务更改为 Restful 样式,然后我们可以通过直接发送 http 请求来调用它。
接口.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(RequestFormat =WebMessageFormat.Json,ResponseFormat =WebMessageFormat.Json)]
string GetData(int value);
}
服务。
public class Service1 : IService1
{
public string GetData(int value)
{
return "<a href='www.test.com.br'>test</a>";
}
}
Web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
</system.serviceModel>
结果(在浏览器中输入地址访问URL是Http Get请求)
或者,我们通过发送 Ajax 请求来调用它。
$.ajax({
method:"Get",
url: "http://10.157.13.69:11000/Service1.svc/GetData?value=34",
contentType:"application/json"
}).done(function(data){
console.log(data);
})
如果有什么我可以帮忙的,请随时告诉我。
我创建了一个简单的 C# WCF 服务,它 returns 一个带有 html 代码的字符串。当我在 WCF 解决方案中使用一个简单的 MVC 项目使用此服务时,everythigs 工作正常。
- 服务代码
public class ConnectorService : IConnectorService
{
public string GetData()
{
return "<a href='www.test.com.br'>test</a>";
}
}
- 接口代码
[ServiceContract]
public interface IConnectorService
{
[OperationContract]
string GetData();
}
此测试后,我在本地 IIS 中发布了此服务,并尝试使用 html 页面使用此服务,该页面不在 WCF 解决方案内,但位于服务的同一 IIS 目录内。
- HTML代码
<html>
<head>
<title>test</title>
<script src='Scripts/jquery-3.3.1.min.js'></script>
</head>
<body>
<div id='divContent'></div>
</body>
</html>
<script type='text/javascript'>
$(document).ready(function () {
$.ajax({
url: 'http://localhost/ConnectorService.svc/GetData',
contentType: 'application/json; charset=utf-8',
type: "GET",
dataType: 'jsonp',
success: function (data) {
$('#divContent').html(data);
},
error: function (error) {
alert("error: status - " + error.status + " | text: " + error.statusText);
}
});
});
</script>
当我在浏览器上打开这个 html 文件时,出现 2 个错误:
1) CORS 策略 - 我用 global.asax 文件修复了这个
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
2) 错误 400 - 错误请求 我尝试了几种堆栈溢出的解决方案,通常会更改我的 ajax 调用、global.asax 和 web.config 文件,但我总是在 chrome 控制台中收到错误的请求错误。
- web.config代码
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Headers" value="Content-Type,Accept" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
我认为这是一个有简单解决方案的简单问题,但是经过几天的测试,我觉得我在追自己的尾巴。有人可以为我提供解决方案吗?
提前致谢。
调用有问题。通常,我们通过使用客户端代理class而不是直接发送http请求来调用典型的WCF服务。
$.ajax({
url: 'http://localhost/ConnectorService.svc/GetData',
contentType: 'application/json; charset=utf-8',
type: "GET",
dataType: 'jsonp',
success: function (data) {
$('#divContent').html(data);
},
error: function (error) {
alert("error: status - " + error.status + " | text: " + error.statusText);
}
这种直接发送http请求调用服务的样式,一般适用于Restful样式的服务,请参考下面的link。
https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design
Asp.net WebAPI 和 WCF 都可以创建 Restful 风格的服务。
https://docs.microsoft.com/en-us/aspnet/web-api/
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/wcf-web-http-programming-model-overview
根据您的示例,我们可以将 WCF 服务更改为 Restful 样式,然后我们可以通过直接发送 http 请求来调用它。
接口.
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebGet(RequestFormat =WebMessageFormat.Json,ResponseFormat =WebMessageFormat.Json)]
string GetData(int value);
}
服务。
public class Service1 : IService1
{
public string GetData(int value)
{
return "<a href='www.test.com.br'>test</a>";
}
}
Web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
</system.serviceModel>
结果(在浏览器中输入地址访问URL是Http Get请求)
或者,我们通过发送 Ajax 请求来调用它。
$.ajax({
method:"Get",
url: "http://10.157.13.69:11000/Service1.svc/GetData?value=34",
contentType:"application/json"
}).done(function(data){
console.log(data);
})
如果有什么我可以帮忙的,请随时告诉我。