项目需要,使用前端直接调用服务端开放接口(本应该是服务端调用),由于域名不同,需要解决跨域名问题。
常见的跨域解决方案:https://segmentfault.com/a/1190000011145364
通过jsonp跨域
• document.domain + iframe跨域
• location.hash + iframe跨域
•window.name + iframe跨域
•postMessage跨域
•跨域资源共享(CORS)
•Access-Control-Allow-Origin
•Nodejs中间件代理跨域
•WebSocket协议跨域
本方案临时采用:Access-Control-Allow-Origin配置方案,在nginx配置了允许跨域访问:
add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
偶尔还是会出现跨域请求失败提示,不是必现,拿到请求代码后模拟,必现了:
Title 发送请求 $(function(){ $('#send').click(function () { var postData ={ "actions":[ {"deviceIdentifier":"A010205-12335", "functionIdentifier":"预置位调用","inputs":{"摄像机Id":"8","预置位编号":"1"}}],"controlNo": "123456543","userId": "21"}; $.ajax({ type: "POST", url: "http://61.155.**.**:38080/api/device/twin/device-service/sync", contentType: 'application/json', data:postData, dataType: "json", success:function (message) { alert("提交成功"+JSON.stringify(message)); }, error:function (message) { alert("提交失败"+JSON.stringify(message)); } }); }); });
提交失败:error:{"readyState":0,"responseText":"","status":0,"statusText":"error"}
使用postman调用,返回正常:
浏览器应该不会弄错,提示跨域肯定是响应头没有返回 Access-Control-Allow-Origin' '*'
,抓包发现,果然响应头没有这个信息,但一看响应体内容是:
{ "code": "internal.server.error", "message": "【系统异常】\norg.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('1' (code 49)): was expecting comma to separate Object entries; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected character ('1' (code 49)): was expecting comma to separate Object entries\n at [Source: (PushbackInputStream); line: 5, column: 34] (through reference chain: com.isyscore.os.twin.run.model.dto.ControlServiceDTO[\"actions\"]->java.util.ArrayList[0])", "detail": "org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('1' (code 49)): was expecting comma to separate Object entries; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected character ('1' (code 49)): was expecting comma to separate Object entries\n at [Source: (PushbackInputStream); line: 5, column: 34] (through reference chain: com.isyscore.os.twin.run.model.dto.ControlServiceDTO[\"actions\"]-...}
OK,这里明白了,由于提交的数据不正常非标准json,导致服务端异常,500,没有正常返回Access-Control-Allow-Origin' '*'
, 即nginx配置的响应头,没有包含500这种异常返回。
网上一搜,也有网友遇到:https://www.dazhuanlan.com/2019/11/23/5dd9465a6643c/
原因和解决办法
原因其实很简单,是因为在 nginx 转发 server 响应的过程中, add_header 只有在 200, 201, 204, 206, 301, 302, 303, 304, 307 状态码时会添加,而 401, 500 都没有添加。
解决:看上面的配置,在 add_header 最后加上 always,可以让 nginx 在非 200, 300 的状态码后面,也使得 add_header 生效。
完整的nginx配置:
add_header 'Access-Control-Allow-Origin' '*' always;add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;