当两个域具有相同的协议(如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()); } }
到这里,跨域问题就解决了。