分享一个头疼了两天的问题哈!相信不少人都会遇到,我是在网上搜了很多解决方案都没能彻底解决;
我遇到的原因是因为 MVC4 升级到 MV5 后发现原先的 POST 接口居然不能跨域了;
试了很多方法,要么是 GET 请求正常了、POST 不正常,要么本地测试正常、发布到线上又异常了。
最终是得感谢这篇文章呐 ^ ^:https://blog.csdn.net/jacky_zh/article/details/72874889
在这里做个总结,希望能给大家提供些帮助吧!水平有限,请多多谅解~
1、跨域说明(以Chrome为参考)
- 如 JS 发起 AJAX 请求的 URL ( IP / Port / Host ) 与当前网页 URL 不同的情况下,均视为跨域请求;
- 由于浏览器的安全限制,默认不允许 JS 跨域请求;
- 当在 JS 发起跨域请求时,浏览器会先将此 URL 以 OPTIONS 的形式向服务端发送 HTTP 请求进行验证;
- 如服务端返回200状态、则告诉浏览器同意此跨域请求,此时浏览器才会真正的向服务端发送用户请求;
(因 此原因才会出现跨域的 POST 请求会被提交2次,不过第一次 OPTIONS 请求是不带 POST 参数的)
- 如服务端返回非200状态时,浏览器就会拒绝此 JS 用户请求,会给 JS 返回一个 “net::ERR_FAILED” 状态、并触发 AJAX 的 error 回调;
2、服务端配置 > Web.config
PS:本地生产环境可以使用 * 号,但发布线上版本切记使用白名单做约束哦!
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true"/>
<!--启用浏览器跨域调用(httpProtocol+handlers)-->
<httpProtocol>
<customHeaders>
<!--定义允许跨域请求的域名(使用","逗号分隔,设为"*"则说明不限制)-->
<add name="Access-Control-Allow-Origin" value="*" />
<!--定义允许跨域请求的Http方法(使用","逗号分隔,设为"*"则说明不限制)-->
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
<!--定义如请求头包含对应属性时就允许跨域(使用","逗号分隔,设为"*"则说明不限制)-->
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<!--<remove name="OPTIONSVerbHandler" /> #注释为解决OPTIONS无法验证问题-->
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
3、服务端配置 > Global.asax.cs
当以上配置后还无法使用的话、那就剩下这至关重要的一步啦!
protected void Application_BeginRequest(object sender, EventArgs e)
{
//浏览器跨域 OPTIONS 验证
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
Response.End(); //返回一个200状态表示允许此跨域请求
}
好了,以上配置完后开始模拟一下接口调用吧!
4、服务端 > 创建测试接口
public class TestController : ApiController
{
/// <summary>
/// get 测试
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
[Route("~/test-get")]
[HttpGet]
public dynamic test_get(string a, string b)
{
return new { a = a, b = b };
}
/// <summary>
/// post 测试
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
[Route("~/test-post")]
[HttpPost]
public dynamic test_post([FromBody] SortedList<string, string> json)
{
return json;
}
}
5、浏览器端 > 模拟跨域调用接口
<script>
//Access to XMLHttpRequest at 'http://localhost:8112/test' from origin 'http://localhost:8115' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
$(function () {
$.ajax({
url: "http://localhost:8112/test-get",
type: "GET",
data:
{
a: 1,
b: 2
},
dataType: "json",
success: function (json) {
console.log(json);
alert('Get调用成功:' + JSON.stringify(json));
},
error: function (request, status, errorThrown) {
console.log(request);
alert('Get调用失败:' + status);
}
});
$.ajax({
url: "http://localhost:8112/test-post",
type: "POST",
contentType: "application/json",
data: JSON.stringify(
{
a: 1,
b: 2
}),
dataType: "json",
success: function (json) {
console.log(json);
alert('Post调用成功:' + JSON.stringify(json));
},
error: function (request, status, error) {
console.log(request);
alert('Post调用失败:' + status);
}
});
});
</script>