为什么默认情况下不允许GET请求返回JSON?

作为ASP.NET MVC 2 Beta 2更新的一部分,默认情况下不允许JSON GET请求。 在从控制器返回JsonResult对象之前,您似乎需要将JsonRequestBehavior字段设置为JsonRequestBehavior

 public JsonResult IsEmailValid(...) { JsonResult result = new JsonResult(); result.Data = ..... ; result.JsonRequestBehavior = JsonRequestBehavior.AllowGet; return result; } 

这背后的原因是什么? 如果我使用JSON GET尝试进行远程validation,我应该使用不同的技术吗?

DenyGet默认的原因是在MSDN上 ,链接到Phil Haack的博客以获取更多详细信息。 看起来像跨站点脚本漏洞。

默认情况下,HTTP GET被禁用,作为ASP.NET跨站请求伪造(CSRF / XSRF)保护的一部分。 如果您的Web服务接受GET请求,那么它们可能容易受到第三方站点的攻击,这些站点通过标签发出请求,并可能通过修改JavaScript setter获取响应。

但值得注意的是,禁用GET请求不足以阻止CSRF攻击,也不是保护您的服务免受上述攻击类型影响的唯一方法。 请参阅针对跨站点请求伪造的强大防御,以便对不同的攻击媒介进行良好分析,以及如何防范它们。

当我将MVC网站从Visual Studio 2008迁移到Visual Studio 2010时,我也遇到了问题。

主aspx在下面,它有一个ViewData,它调用一个Category Controller,以便用SelectList集合填充ViewData [“Categories”]。 还有一个脚本可以调用子类别控制器来用javascript填充第二个组合。 现在我能够修复它在第二个控制器上添加AlloGet属性。

这是aspx和javascript

     <% using (Html.BeginForm()) {%>  <%= Html.DropDownList("CategoryId", (SelectList)ViewData["Categories"], "--categories--") %> <%= Html.ValidationMessage("category","*") %> 
<%=Html.Hidden("chosenSubcategory", TempData["subcategory"])%> <%= Html.ValidationMessage("subcategory", "*")%> <%}%>

这是我的子类别控制器

 public class SubcategoryController : Controller { private MyEntities db = new MyEntities(); public int SubcategoryId { get; set; } public int SubcategoryName { get; set; } public JsonResult Subcategories(int? categoryId) { try { if (!categoryId.HasValue) categoryId = Convert.ToInt32(RouteData.Values["id"]); var subcategories = (from c in db.Subcategories.Include("Categories") where c.Categories.CategoryId == categoryId && c.Active && !c.Deleted && c.Categories.Active && !c.Categories.Deleted orderby c.SubcategoryName select new { SubcategoryId = c.SubcategoryId, SubcategoryName = c.SubcategoryName } ); //just added the allow get attribute return this.Json(subcategories, JsonRequestBehavior.AllowGet); } catch { return this.Json(null); } } 

我不知道这是否是他们选择更改默认值的原因,但这是我的经验:

当某些浏览器看到GET时,他们认为可以缓存结果。 由于AJAX通常用于从服务器获取最新信息的小请求,因此缓存这些结果通常会导致意外行为。 如果您知道给定的输入每次都会返回相同的结果(例如“密码”不能用作密码,无论您何时问我),那么GET就可以了,浏览器缓存实际上可以提高性能有人尝试多次validation相同的输入。 另一方面,如果您希望根据服务器端数据的当前状态(“myfavoriteusername”可能在2分钟前可用,但从那时起已经采用),您希望得到不同的答案,那么您应该使用POST来避免浏览器认为第一个响应仍然是正确的。