
服務器端解決,通過一個filter過濾來自移動端服務器的請求,為response添加Access-Control-Allow信息。通過設置Access-Control-Allow-Credentials=true允許客戶端發(fā)送cookie,客戶端需要設置XMLHttpRequest()的withCredentials 屬性為true
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
在ionic中需要設置$http:
$http({
method: "GET",
url: url,
params: params,
cache: false,
timeout: 20000,
withCredentials:true,
headers: {'Content-Type': 'application/json;charset=UTF-8','Cache-Control':'no-cache'}
}).then(function (result) {
...
}
跨域小知識
客戶端ClientA請求服務器server1,server1的頁面中使用ajax請求了server2中的數(shù)據(jù)就發(fā)生了跨域。默認情況,瀏覽器不允許跨域請求。大致解決思路有:
瀏覽器端解決。
適合開發(fā)者自己調試, 在chrome瀏覽器中添加啟動參數(shù):
--args --disable-web-security --user-data-dir
server端解決方案JSONP。
通過某些手段規(guī)避瀏覽器的跨域規(guī)則,比如使用JSONP等,JSONP需要客戶端與服務器端配合。
網(wǎng)頁通過動態(tài)插入<script>元素,由它向跨源網(wǎng)址發(fā)出請求,不再受跨域規(guī)則限制。
推薦JQuery,在ajax請求中指定dataType:'jsonp'的方式。這種方式自動實現(xiàn)<script>加回調函數(shù)的效果。
js代碼
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$.ajax({
url:"http://crossdomain.com/services.php",
dataType:'jsonp',
data:'',
jsonp:'callback',
success:function(result) {
for(var i in result) {
alert(i+":"+result[i]);//循環(huán)輸出a:1,b:2,etc.
}
},
timeout:3000
});
</script>
這種方法需要js實現(xiàn)處理返回結果的回調函數(shù),如果有很多頁面跨域,實現(xiàn)這些回調函數(shù)挺煩人的。
服務器端實現(xiàn),在原來的返回結果基礎上添加回調函數(shù)名稱和括號,默認用success,也可以配合jQuery的ajax請求指定函數(shù)名稱。
支持跨域前的返回:
['data1','data2']
為支持jsonp,修改后的返回:
callbackFunction(['data1','data2'])
server端實現(xiàn)方案2,通過Allow-Control-Access機制。
現(xiàn)代瀏覽器都通過Allow-Control-Access機制允許跨域,原理如下:
- 瀏覽器發(fā)現(xiàn)存在跨域請求,不直接拒絕,而是向服務器server2發(fā)多送一個Origin字段把server1的IP地址加端口告知server2,如果是put、delete這種高危請求,瀏覽器先發(fā)送一個options類型的請求。
- 如果server2沒有任何允許跨域的意思,瀏覽器不再處理服務器的響應,而是報一個跨域錯誤。
- 如果server2允許跨域,需要在response中通知瀏覽器,告知瀏覽器允許誰跨域,允許不允許瀏覽器發(fā)送cookie信息。
- 瀏覽器檢查server2返回的信息,如果當前請求合乎規(guī)則,則進一步處理服務器端響應,執(zhí)行js,展示頁面。
server2允許跨域的java端實現(xiàn),通過filter為response添加Allow-Control-Access信息:
package org.example.core.filter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jodd.util.StringUtil;
/**
* @author damowang 20170802 解決移動端開發(fā)瀏覽器跨域問題
*
*/
public class CORSFilter implements Filter {
/**客戶端域名,通過init-param配置,在filter初始化時賦值*/
private String allowOrigin;
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) sresponse;
HttpServletRequest request = (HttpServletRequest) srequest;
//設置允許誰(server1的域名或ip)跨域,在一次request中Access-Control-Allow-Methods只能設置一個客戶端地址,因此通過判斷客戶端設置該字段
if (StringUtil.isNotEmpty(allowOrigin)) {
List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));
String currentOrigin = request.getHeader("Origin");
if (allowOriginList.contains(currentOrigin)) {
response.setHeader("Access-Control-Allow-Origin", currentOrigin);
}
}
response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
response.setHeader("Access-Control-Allow-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,Cache-Control,Content-Type");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
allowOrigin = filterConfig.getInitParameter("allowOrigin");
}
}
web.xml中配置攔截器
<!-- 跨域攔截器 -->
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>org.example.core.filter.CORSFilter</filter-class>
<init-param>
<param-name>allowOrigin</param-name>
<param-value>http://server1.com:8100,http://anotherDomainOfServer1.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
客戶端允許發(fā)送cookie:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;