什么是跨域?
由于浏览器的同源策略,不允许跨域调用其他页面的对象。所谓跨域是指跨域名。同一域名是指协议、域名、端口三者均相同,任一不同都不属于同一域名,举例如下:
当网站http://www.domain.com/work.html文件中发起一个ajax请求时,若请求的URL为下列情况时,跨域结果如下:
URL | 说明 | 是否跨域 |
---|---|---|
http://www.domain.com/user | 同一协议,同一域名,同一端口 | 否 |
https://www.domain.com/user | 不同协议,同一域名,同一端口 | 是 |
http://www.baidu.com/user | 同一协议,不同域名,同一端口 | 是 |
http://www.domain.com:8000/user | 同一协议,同一域名,不同端口 | 是 |
如何实现跨域请求?
1.跨域资源共享 CORS
CORS是W3C推出一个标准,它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS 使用条件:
浏览器支持:ie10+
服务端支持(以java为例,添加一个过滤器):
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CrossDomainFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(CrossDomainFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
logger.warn("filter init--------------------");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 跨域
String origin = httpRequest.getHeader("Origin");
if (origin == null) {
origin = "*";
}
logger.warn("进来了,Origin:{},Method:{}",origin,httpRequest.getMethod());
//解决跨域的关键
httpResponse.addHeader("Access-Control-Allow-Origin", origin);
httpResponse.addHeader("Access-Control-Allow-Headers", "Origin, x-requested-with, Content-Type, Accept,X-Cookie");
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,OPTIONS,DELETE");
if (httpRequest.getMethod().equals("OPTIONS")) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(request, response);
} catch (Exception e) {
logger.error("Exception in crossDomainFilter.doFilter", e);
throw e;
}
}
@Override
public void destroy() {
}
}
2.JSONP
由于JSONP是动态增加script标签完成跨域的,又因为script标签只能发送get请求 所以JSONP只支持GET这一种请求方式
ajax代码:
$.ajax({
type: 'GET',
url: 'http://dev.domain.com:8080/name',
data: {
name: "yuruixin"
},
dataType: 'jsonp',
jsonp: "callback",
success: function (data) {
console.info(data);
}
});
后台controller代码:
@RequestMapping(value = "/name",method = RequestMethod.GET)
@ResponseBody
public void getName(String name, String callback, HttpServletResponse response) throws IOException {
Map map = new HashMap();
map.put("name","query user:"+name);
PrintWriter pw = response.getWriter();
pw.write(callback+"(\""+name+"\")");
pw.close();
pw = null;
}
以上,CORS和JSONP都可以实现跨域,若不要求浏览器兼容至ie10以下,建议采用CORS方式,该方式代码侵入性小,使用方便。JSONP虽然可以支持老版本浏览器,但是不支持GET以外的请求方式,且对代码入侵较大