IIS Express与Authentication的导致的Bug

最近在公司写一个ASP.NET的项目,在测试过程中遇到了一个大坑。

首先为了方便前后端分离,我把WebAPI与用来显示的WebSite分成了两部分。显然这会导致出现跨域访问的问题。当然这个老生常谈的问题非常容易解决,只需要在服务器端响应头加上:

Access-Control-Allow-Origin:*  
Access-Control-Allow-Methods:*  
Access-Control-Allow-Headers:*  

(只是举个例子,当然这么做不太安全)

上面这个问题是预料之中的所以很容易就解决了,而接下来发生的问题非常罕见。

由于整个项目只会(只能)在公司内网运行,所以整个项目使用了Windows Authentication,并且禁用了Anonymous。然后由于每一个Solution同时只能运行Project,所以我将WebAPI部分写好之后直接Publish到了远程服务器,而在本地运行这个WebSite来访问远在其他服务器上的WebAPI。当然我也在远程IIS上正确地开启了Windows Authentication。

在写的过程中,我遇到了WebAPI的一些BUG,需要进行调试。而VS对ASP.NET项目远程调试配置方式还是挺麻烦的。这时候我就想到了在本地运行WebAPI项目。然后将WebSite直接在文件系统中通过浏览器打开,这时候发现之前写的ajax出问题访问不了。

错误提示是跟之前遇到的跨域问题一样。No 'Access-Control-Allow-Origin' 云云。然而跨域我明明已经配置正确了。

所以这个时候的现象是:同样的WebSite代码,同样的WebAPI代码,远程的WebAPI能跨域访问,而本地的WebAPI不能跨域访问。

调试了许久无果,我开始尝试用Fiddler从HTTP报文中抓包分析。并且尝试在整个ASP.NET的执行流程,而非我自己写的Controller内部添加断点。

根据ASP.NET项目的执行流程,首先程序在收到Request之后会经过一系列处理交给我的Controller,然后将处理的结果传递给后面的ActionFilter。通过设置断点我发现我定义的ActionFilter的断点根本没有被触发,所以程序根本没进入到我的Controller中!

这时候就大致估计出问题在哪里了:权限问题。由于IIS Express可以设置的地方很少,所以我忘记设置Windows Authentication,所以真正的问题所在并不是跨域问题,而是在我的ajax请求发出之后,WebAPI直接拒绝了该请求,并且发回了一个错误页面,而权限验证早在进入我的Controller之前就会进行,更不用说后面的ActionFilter。这最终导致了Response中没有包含我故意添加的Access-Control-Allow-Origin等信息(能在Fiddler中发现)。所以在浏览器中提示的错误是“No Access-Control-Allow-Origin”。知道了问题所在就非常好办了,只需要修改(VS15)项目文件夹下.vs\config\applicationhost.config文件和\Documents\IISExpress\config\applicationhost.config文件,设置即可。

写到这里我突然想起来,在创建项目的时候,我考虑到了要使用Windows验证,所以在创建WebAPI项目的向导中特意选择了使用Windows Authentication,而在创建WebSite项目的时候忘记选择了,或许在这里选择正确就不会遇到上面这一大堆麻烦了。

一种比较难调试的bug就是被错误信息误导的bug。所以我们需要从一些蛛丝马迹中发现错误的真正原因再加以改正。

Friskit

继续阅读此作者的更多文章