之前写一篇 fetch 跨域请求解决方法的问题,当时使用的是 get 请求
当时使用了第二次解决方法,在Reponse的Headers上添加控制设置项
在使用 fetch 进行 post 跨域请求时,出现新的问题
post请求代码如下:
fetch('http://localhost:57437/api/ReactDashboard/GetVehicleInfoArray',
{
method: 'POST',
headers:{
'Content-Type':'application/json; charset=utf-8'
},
body: {
factoryCodeList
}
}).then(res => {
console.log(res);
return res.json();
}).then(json => {
console.log('获取的结果', json);
return json;
}).catch(err => {
console.log('请求错误', err);
})
分析报错结果发现很奇怪,明明是POST请求,为什么报OPTIONS操作出错
OPTIONS http://localhost:57437/api/ReactDashboard/GetVehicleInfoArray net::ERR_ABORTED 405 (Method Not Allowed)
首先,搞清楚 HTTP 405 的定义:
HTTP 405
请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。 鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。
其次,分析为什么请求变成了 OPTIONS 操作,经查找资料分析:
不仅仅是fetch,只要你满足以下几种情况,都会去发起一个 Preflighted requests,也就是options请求,参见链接:
HTTP access control (CORS)
- It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, ortext/plain, e.g. if the POST request sends an XML payload to the server using application/xmlor text/xml application/json, then the request is preflighted.
- It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
触发这几个条件中的其中一种了吧,浏览器在发起跨域请求的时候会带着一个Origin
header,那么其实就是个custom headers,那么也就会先触发一个Preflighted requests,
Fetch Standard 也有提到。
(1)在web应用服务器上(如IIS)中的 HTTP响应头
设置中添加相应CORS的配置
Access-Control-Allow-Credentials : true
Access-Control-Allow-Headers : *
Access-Control-Allow-Methods : PUT,POST,GET,DELETE,OPTIONS
Access-Control-Allow-Origin : http://localhost:8000
(2)在web应用启动时,添加CORS配置,如果的 C# web api 可以使用Nuget搜索microsoft.aspnet.webapi.cors
组件进行CORS相关配置。可参考博文C#进阶系列——WebApi 跨域问题解决方案:CORS
前端代码:
fetch('http://localhost:57437/api/ReactDashboard/GetVehicleInfoArray',
{
method: 'POST',
headers:{
'Content-Type':'application/json'
},
body: factoryCodeList
}).then(res => {
console.log(res);
return res.json();
}).then(json => {
console.log('获取的结果', json);
return json;
}).catch(err => {
console.log('请求错误', err);
})
后端代码:
[HttpPost]
public List GetVehicleInfoArray(string[] factoryCodeList)
{
//TODO ACTIONS
return vehicleInfoList;
}
(3)使用原始的content-type application/x-www-form-urlencoded
进行带参数 POST
操作,避免发起Preflighted requests,也就是options请求
前端代码:
fetch('http://localhost:57437/api/ReactDashboard/GetVehicleInfoArray',
{
method: 'POST',
headers:{
'Content-Type':'application/x-www-form-urlencoded'
},
body: {
factoryCodeList
}
}).then(res => {
console.log(res);
return res.json();
}).then(json => {
console.log('获取的结果', json);
return json;
}).catch(err => {
console.log('请求错误', err);
})
后端代码(C# web api):
[HttpPost]
public HttpResponseMessage GetVehicleInfoArray([FromBody]JObject param)
{
dynamic obj = param;
string[] factoryCodeList = ((JArray)obj.indexArray).ToObject();
//TODO ACTIONS
return httpResponseMessage;
}