IIS 8.5 在使用 Post 方法调用 REST WS 时在生产中抛出 400 错误请求
IIS 8.5 throwing 400 Bad request in Production when calling REST WS using Post method
我有一个奇怪的问题。下面我一步步详细解释一下:
我有一家供应商开发了 REST WS(使用 WCF 制作)用于与 MS CRM 同步数据。
我开发了一个 windows 服务,它从数据库中获取要同步的批量数据,然后使用 Post 方法将其传递给此 Web 服务 JSON对象。 windows 服务部署在其中一个节点上。
我面临的问题在开发、QA、UAT 或暂存环境中从未发生过。仅生产环境独有。
在生产环境中,应用程序工作了一段时间,然后开始抛出 400 Bad request 错误。然后,直到我们重新启动站点或重置 App Pool Identity,IIS 一直抛出 400 Bad request 错误。当我们重新启动站点或应用程序池时,失败的相同请求开始获得成功响应。它像这样工作了一段时间,然后又开始发生 400 次。
托管web服务的环境是Win Server 2012,2节点负载均衡环境。 WS部署在两个节点的8080端口,.Net 4.0下配置为运行.
我在我的 Windows 服务日志中收到以下错误,这是这些 WS 的客户端。
System.Net.WebException: The remote server returned an error: (400)
Bad Request.
at SspToCrmSynchronizationService.Helpers.CrmWrapperWsHelper.CallService(String
data, String url, String method, String userName, String password,
String contentType) in CrmWrapperWsHelper.cs:line 79
at SspToCrmSynchronizationService.Helpers.CrmWrapperWsHelper.CallDocumentCreateService(String
data) in CrmWrapperWsHelper.cs:line 20
at SspToCrmSynchronizationService.Process.CommonOperations.GenerateJsonAndInvokeDocCreateWS(Int64
appRefNo, Application app) in CommonOperations.cs:line 52
at SspToCrmSynchronizationService.Process.SequentialProcess.Process(List`1
appList, DatabaseHelper dbHelperForChildTask, CancellationToken ct) in
SequentialProcess.cs:line 88
首先我们检查了 IIS 日志,发现 IIS 在短短 100 毫秒内返回了 400 错误。我们怀疑它没有到达 WS 应用程序,因为应用程序根本没有记录任何东西,尽管记录请求是供应商在 WS 代码中做的第一件事。
其次我们使用Fiddler抓取请求和响应,得到如下:
HTTP/1.1 400 Bad Request
Cache-Control: private
Content-Length: 1647
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-ASpNet-Version: 4.0.30319
X-Powered-By: ASP.Net
Date: Tue, 17 Oct 2017 07:14:26 GMT
- 然后我们检查了 IIS Httperr.log。在日志中,我们发现了一些请求的以下内容,而不是每个失败请求的内容。好像什么都没有。
2017-07-07 03:32:45 10.102.2.52 63726 10.102.2.52 8080 - - - - - Timer_ConnectionIdle -
2017-07-08 22:46:55 10.102.2.52 50916 10.102.2.52 8080 - - - - - Timer_ConnectionIdle -
2017-07-08 22:55:09 10.102.2.52 51004 10.102.2.52 8080 - - - - - Timer_ConnectionIdle -
- 我们在 IIS 中为 400 配置了失败的跟踪日志,并在抛出此 400 错误时在跟踪日志中收到一条警告。由于 NDA 和安全原因,我已经从图像中删除了一些数据。
基本上Warning详情如下:
124. MODULE_SET_RESPONSE_ERROR_STATUS
ModuleName="ManagedPipelineHandler",
Notification="EXECUTE_REQUEST_HANDLER",
HttpStatus="400",
HttpReason="Bad Request",
HttpSubStatus="0",
ErrorCode="The operation completed successfully. (0x0)",
ConfigExceptionInfo=""
- 之后我比较了一个错误案例和一个成功案例。下面是图像。我注意到,在失败的情况下 General_Read_Entity_Start 和 General_Read_Entity_End 根本没有发生。
我能理解的最大程度是 IIS 无法以某种方式将 JSON 字符串解析为某些实体,AppPool 崩溃然后开始抛出 400 错误,直到 AppPool 或 IIS 重置未完成。我不知道是什么原因造成的(根本原因),也不知道如何解决这个问题,以及为什么它一开始能正常工作,但一段时间后就不起作用了。任何帮助将不胜感激。
[编辑]
- 服务器上的资源消耗不到 10%。
- 对于成功案例,WS 的平均响应时间为 5 秒,而对于错误案例,它 returns 在 100 毫秒内。
- 我们对大约 100 多个请求的测试服务进行了压力测试,一切正常。
重启后"stop working"的时间还一样吗?它是否随着服务经过的假定流量呈线性变化?您 stress/spike 测试过该服务了吗?您是否监控过托管服务器的资源?
如果它似乎只发生在 Prod 上,这与测试服务器没有什么不同,预计 Prod 被未知数量的来源使用。
首先,我会确保资源与此无关。 (有点疯狂:如果不违反用户权限,将产品的 in 请求镜像到具有类似功能的测试服务器之一,看看会发生什么)
我们需要了解它是如何工作的,有很多条件:
我们在 JSON 中传递了一个日期时间值。在 WS 端,当我们案例中的 WS 容器(IIS 和 WCF)试图将 DateTime 字段传递给应用程序时,DateTime 值引发了一些解析错误,但未能进行转换。我相信这可能是由于语言环境。我们通过在 WS accepted JSON.
中将日期时间更改为字符串来修复它
第二个问题是我们的供应商使用 WCF 作为创建 RestAPI 的技术。 WCF 的一种行为是,如果来自客户端的请求导致 WS 容器中发生致命异常,则 IIS 会将此客户端注册到阻止列表中,并且不会将来自同一客户端的请求转发到应用程序,直到 IIS 重新启动完毕。 IIS 将不断向我们返回 Bad Request 状态消息。
我有一个奇怪的问题。下面我一步步详细解释一下:
我有一家供应商开发了 REST WS(使用 WCF 制作)用于与 MS CRM 同步数据。
我开发了一个 windows 服务,它从数据库中获取要同步的批量数据,然后使用 Post 方法将其传递给此 Web 服务 JSON对象。 windows 服务部署在其中一个节点上。
我面临的问题在开发、QA、UAT 或暂存环境中从未发生过。仅生产环境独有。
在生产环境中,应用程序工作了一段时间,然后开始抛出 400 Bad request 错误。然后,直到我们重新启动站点或重置 App Pool Identity,IIS 一直抛出 400 Bad request 错误。当我们重新启动站点或应用程序池时,失败的相同请求开始获得成功响应。它像这样工作了一段时间,然后又开始发生 400 次。
托管web服务的环境是Win Server 2012,2节点负载均衡环境。 WS部署在两个节点的8080端口,.Net 4.0下配置为运行.
我在我的 Windows 服务日志中收到以下错误,这是这些 WS 的客户端。
System.Net.WebException: The remote server returned an error: (400) Bad Request. at SspToCrmSynchronizationService.Helpers.CrmWrapperWsHelper.CallService(String data, String url, String method, String userName, String password, String contentType) in CrmWrapperWsHelper.cs:line 79 at SspToCrmSynchronizationService.Helpers.CrmWrapperWsHelper.CallDocumentCreateService(String data) in CrmWrapperWsHelper.cs:line 20 at SspToCrmSynchronizationService.Process.CommonOperations.GenerateJsonAndInvokeDocCreateWS(Int64 appRefNo, Application app) in CommonOperations.cs:line 52 at SspToCrmSynchronizationService.Process.SequentialProcess.Process(List`1 appList, DatabaseHelper dbHelperForChildTask, CancellationToken ct) in SequentialProcess.cs:line 88
首先我们检查了 IIS 日志,发现 IIS 在短短 100 毫秒内返回了 400 错误。我们怀疑它没有到达 WS 应用程序,因为应用程序根本没有记录任何东西,尽管记录请求是供应商在 WS 代码中做的第一件事。
其次我们使用Fiddler抓取请求和响应,得到如下:
HTTP/1.1 400 Bad Request Cache-Control: private Content-Length: 1647 Content-Type: text/html Server: Microsoft-IIS/8.5 X-ASpNet-Version: 4.0.30319 X-Powered-By: ASP.Net Date: Tue, 17 Oct 2017 07:14:26 GMT
- 然后我们检查了 IIS Httperr.log。在日志中,我们发现了一些请求的以下内容,而不是每个失败请求的内容。好像什么都没有。
2017-07-07 03:32:45 10.102.2.52 63726 10.102.2.52 8080 - - - - - Timer_ConnectionIdle -
2017-07-08 22:46:55 10.102.2.52 50916 10.102.2.52 8080 - - - - - Timer_ConnectionIdle - 2017-07-08 22:55:09 10.102.2.52 51004 10.102.2.52 8080 - - - - - Timer_ConnectionIdle -
- 我们在 IIS 中为 400 配置了失败的跟踪日志,并在抛出此 400 错误时在跟踪日志中收到一条警告。由于 NDA 和安全原因,我已经从图像中删除了一些数据。
基本上Warning详情如下:
124. MODULE_SET_RESPONSE_ERROR_STATUS ModuleName="ManagedPipelineHandler", Notification="EXECUTE_REQUEST_HANDLER", HttpStatus="400", HttpReason="Bad Request", HttpSubStatus="0", ErrorCode="The operation completed successfully. (0x0)", ConfigExceptionInfo=""
- 之后我比较了一个错误案例和一个成功案例。下面是图像。我注意到,在失败的情况下 General_Read_Entity_Start 和 General_Read_Entity_End 根本没有发生。
我能理解的最大程度是 IIS 无法以某种方式将 JSON 字符串解析为某些实体,AppPool 崩溃然后开始抛出 400 错误,直到 AppPool 或 IIS 重置未完成。我不知道是什么原因造成的(根本原因),也不知道如何解决这个问题,以及为什么它一开始能正常工作,但一段时间后就不起作用了。任何帮助将不胜感激。
[编辑]
- 服务器上的资源消耗不到 10%。
- 对于成功案例,WS 的平均响应时间为 5 秒,而对于错误案例,它 returns 在 100 毫秒内。
- 我们对大约 100 多个请求的测试服务进行了压力测试,一切正常。
重启后"stop working"的时间还一样吗?它是否随着服务经过的假定流量呈线性变化?您 stress/spike 测试过该服务了吗?您是否监控过托管服务器的资源?
如果它似乎只发生在 Prod 上,这与测试服务器没有什么不同,预计 Prod 被未知数量的来源使用。 首先,我会确保资源与此无关。 (有点疯狂:如果不违反用户权限,将产品的 in 请求镜像到具有类似功能的测试服务器之一,看看会发生什么)
我们需要了解它是如何工作的,有很多条件:
我们在 JSON 中传递了一个日期时间值。在 WS 端,当我们案例中的 WS 容器(IIS 和 WCF)试图将 DateTime 字段传递给应用程序时,DateTime 值引发了一些解析错误,但未能进行转换。我相信这可能是由于语言环境。我们通过在 WS accepted JSON.
中将日期时间更改为字符串来修复它
第二个问题是我们的供应商使用 WCF 作为创建 RestAPI 的技术。 WCF 的一种行为是,如果来自客户端的请求导致 WS 容器中发生致命异常,则 IIS 会将此客户端注册到阻止列表中,并且不会将来自同一客户端的请求转发到应用程序,直到 IIS 重新启动完毕。 IIS 将不断向我们返回 Bad Request 状态消息。