当两个域具有相同的协议(如http), 相同的端口(如80),相同的host(如https://www.test.com:8080),那么我们就可以认为它们是相同的域(协议,域名,端口都必须相同)。
跨域就指协议,域名,端口不一致,出于安全考虑,跨域的资源之间是无法交互的 (例如:一般情况跨域的 JavaScript 无法交互,当然有很多解决跨域的方案,这里讲给出使用 Access-Control-Allow-Origin 头字段来解决)。
Access-Control-Allow-Origin 头字段是 HTML5 中定义的一种解决资源跨域的策略。他是通过服务器端返回带有 Access-Control-Allow-Origin 标识的 Response header,用来解决资源的跨域权限问题。
使用方法,在response添加 Access-Control-Allow-Origin,例如
Access-Control-Allow-Origin: https://www.test1.com
https://www.test1.com 是访问的域名,根据实际情况设置。
也可以设置为 * 表示该资源谁都可以用
Access-Control-Allow-Origin: *
如果资源是html页面,可以设置
<meta http-equiv="Access-Control-Allow-Origin" content="*">
实例:假如我们有两个应用,分别是 webapp_account(访问地址:https://www.account.com:8081/account) 和 webapp_payment(访问地址:https://www.payment.com:8082/payment),然后 webapp_payment 应用通过JS代码调用 webapp_account 的的服务。
webapp_account 提供了一个 AccountInfoServlet 服务,用来获取用户基本信息。代码如下:
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class AccountInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("#### start......" + System.currentTimeMillis());
// 设置返回数据的类型
resp.setHeader("Content-Type", "application/json");
JSONObject json = new JSONObject();
try {
json.put("id", "10010");
json.put("name", "Bill");
json.put("sex", "male");
} catch (Exception e) {
e.printStackTrace();
json.put("errorMessage", e.getMessage());
} finally {
PrintWriter writer = resp.getWriter();
writer.print(json.toJSONString());
writer.flush();
writer.close();
}
System.out.println("#### end......" + + System.currentTimeMillis());
}
}webapp_payment 应用在前段页面通过JS访问 AccountInfoServlet 服务。代码如下:
<button id="btnTest">调用webapp_account</button>
<script type="text/javascript">
$("#btnTest").click(function(){
$.getJSON("https://www.account.com:8081/account/servlet/accountInfoServlet", function(ret){
console.debug(ret);
});
});
</script>执行上面的JS调用抛出了如下错误信息:
Failed to load https://www.account.com:8081/account/servlet/accountInfoServlet: The 'Access-Control-Allow-Origin' header contains the invalid value 'www.payment.com'. Origin 'https://www.payment.com:8082' is therefore not allowed access.
从上面的错误信息得知,出现了跨域错误。下面通过在 AccountInfoServlet 设置 Access-Control-Allow-Origin 头字段来解决。代码如下:
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 该服务提供给 webapp_payment 进行调用,此时将抛出跨域错误信息。
* 我们通过响应的 Access-Control-Allow-Origin 头字段来控制是否允许跨域访问。
*/
public class AccountInfoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("#### start......" + System.currentTimeMillis());
// 设置返回数据的类型
resp.setHeader("Content-Type", "application/json");
// 设置允许 www.payment.com 域进行跨域访问
// resp.setHeader("Access-Control-Allow-Origin", "https://www.payment.com:8082");
// 允许任何域名都能访问
resp.setHeader("Access-Control-Allow-Origin", "*");
JSONObject json = new JSONObject();
try {
json.put("id", "10010");
json.put("name", "Bill");
json.put("sex", "male");
} catch (Exception e) {
e.printStackTrace();
json.put("errorMessage", e.getMessage());
} finally {
PrintWriter writer = resp.getWriter();
writer.print(json.toJSONString());
writer.flush();
writer.close();
}
System.out.println("#### end......" + + System.currentTimeMillis());
}
}到这里,跨域问题就解决了。