使用JavaScript发送POST请求到WCF服务时出现400错误的请求错误

时间:2019-12-05 23:41:50

标签: javascript c# wcf post

我有一个非常简单的自托管WCF应用程序,该应用程序是通过以下方式初始化的:

Host = new WebServiceHost(this, new Uri(serviceAddress));
var binding = new WebHttpBinding();
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.CrossDomainScriptAccessEnabled = true; // TODO: Remove this?
var endpoint = Host.AddServiceEndpoint(typeof(HttpService), binding, "");
Host.Open();

我的HttpService类具有此方法:

[OperationContract, WebInvoke(Method = "*")]
public string Evaluate(string query)
{
    WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");

    if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
    {
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, PUT, DELETE");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
        WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Max-Age", "1728000");
        return "";
    }
    else
    {
        try
        {
            return "12345";
        }
        catch (ProcessNotFoundException ex)
        {
            throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.NotFound);
        }
        catch (Exception ex)
        {
            throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
        }
    }
}

我在上面添加了CORS内容,以便任何人都可以从任何使用JavaScript的网站使用此API。而且我正在尝试使用fetch运行一些POST请求,因为一旦它起作用,我将传递大量数据,因此GET方法将不起作用。通过JavaScript执行以下操作可以正常运行:

fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '1232'});

这样做时,我的Evaluate方法首先被OPTIONS调用,然后被POST调用,并且返回的XML字符串没有错误。以下内容也适用(请注意正文中的引号):

fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '"hello world"'});

由于两个都是有效的JSON,尽管任何JSON字符串都可以使用,所以我做到了这一点,但出现了400错误的请求错误:

fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '[10]'});

我想也许它想要一个可以转换为我的方法参数的JSON,但这也不起作用(给我400错误):

fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: JSON.stringify({ query: "hey" })})

所以它可以带数字和字符串,但不能带别,我也不知道为什么。我尝试使用所有其他这些属性组合,并获得了完全相同的结果:

[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped)]

我只想能够发送任何字符串,而无需检查它并确定它的好坏,同时还能够执行上面的CORS事情。有办法吗?

2 个答案:

答案 0 :(得分:0)

我找到了一种解决方法,但是我仍然不确定为什么它让我传递数字和字符串而不是数组,因此,如果有人提出实际的解释,我很乐意接受。我的解决方案是在Evaluate方法中采用Stream而不是字符串,然后读取流:

using (var memoryStream = new MemoryStream())
{
    query.CopyTo(memoryStream);
    var array = memoryStream.ToArray();
    var lole = Encoding.UTF8.GetString(array);
}

我的想法是,由于我正在做CORS事情,并且浏览器在发送OPTIONS请求时发送了一个空的正文,因此WCF无法将其作为JSON处理,因此我必须自己处理一切并通过采取战争流来做到这一点。仍然不知道为什么它让我发送数字和字符串(以及BTW也为布尔值),但没有数组(或对象)。

答案 1 :(得分:0)

首先,以下定义仅支持使用request body而不是URL参数来接受参数。

[OperationContract, WebInvoke(Method = "*")]
public string Evaluate(string query)

此外,默认情况下,参数的主体样式为裸露。 BodyStyle =WebMessageBodyStyle.Bare 这意味着服务器接受字符串而不包装参数名。

  

body:“ 1232”
  正文:““ hello world”'

当我们手动将值切换为BodyStyle=WebMessageBodyStyle.Wrapped时,服务器将接受以下格式。基本上,您的尝试是正确的。这里只是一个小问题。

{"value":"abcd"}

这是我的例子,希望对您有帮助。
服务器合同。

[OperationContract]
        [WebInvoke(Method ="*",BodyStyle =WebMessageBodyStyle.Wrapped,ResponseFormat =WebMessageFormat.Json)]
        string GetData(string value);


JS

 <script>
        var para1 = { "value": "abcdefg" };
        $.ajax({
            type: "POST",
            url: "http://localhost:8864/Service1.svc/getdata",
            data: JSON.stringify(para1),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: OnSuccessCall,
            error: OnErrorCall
        });
        function OnSuccessCall(response) {
            console.log(response);
        }
        function OnErrorCall(response) {
            console.log(response.status + " " + response.statusText);
        }
</script>

关于处理CORS问题,我添加了一个额外的global.asax文件。

protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With,Accept");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }

这是相关文件。
https://docs.microsoft.com/en-us/dotnet/api/system.servicemodel.web.webmessagebodystyle?view=netframework-4.8
请随时告诉我是否有什么我可以帮助的。