Servlet中跨域问题详解
一、什么是跨域
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
浏览器从一个域名的网页去请求另一个域名的资源时,出现协议、域名、端口、任一不同,都属于跨域。
比如在百度的一个页面当中,访问京东商城当中的某个资源。这就是跨域。
跨:跨过。
域:区域。
二、环境搭建
资料地址:
链接:https://pan.baidu.com/s/1vMserxHqN75EeeL78Sr4WA
提取码:o5j5
- 1、新建一个空项目,名称为:跨域Demo
- 2、建立两个Web项目:A-Model,B-Model
- 3、对两个框架添加WEB框架支持
- 4、添加lib依赖:JSP跟Servlet依赖(tomcat下的lib包下就有)
- 5、为两个模块配置Tomcat,A模块请求路径为:localhost:8080/a B模块的请求路径为:localhost:8081/b
三、可以跨域的请求
1、在哪些请求的情况下,跨域没有问题呢?
- 超链接
- form表单
- window.location.href
- document.location.href
- img: src属性
- script: src属性
只要是以上的请求,跨域都是被允许的。都可以实现。
2、测试以上的请求是否可以自动跨域访问:
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试哪些请求是可以跨域访问的。title>
head>
<body>
<a href="http://localhost:8081/b/index.html">访问b站点当中的index页面a>
<br><br>
<form action="http://localhost:8081/b/user/reg" method="post">
username:<input type="text" name="username"><br>
password:<input type="password" name="password"><br>
<input type="submit" value="注册">
form>
<br>
<button id="btn1" onclick="window.location.href='http://localhost:8081/b/index.html'">b站点当中的index页面button><br>
<button id="btn2" onclick="document.location.href='http://localhost:8081/b/index.html'">b站点当中的index页面button><br>
<img src="http://localhost:8081/b/img/bg_logo.png" width="100px" />
<script type="text/javascript" src="http://localhost:8081/b/js/my.js">script>
body>
html>
1、超连接
2、form表单
3、测试以下四种的跨域访问
window.location.href
document.location.href
img: src属性
script: src属性
四、不可以跨域的请求
使用XMLHttpRequest对象发送AJAX请求的时候不能跨域!!!
为什么使用XMLHttpRequest对象发送AJAX请求不能跨域呢?
- XMLHttpRequest是浏览器内置的对象。(javascript内置的对象)
- XMLHttpRequest对象一旦创建之后会一直存储在浏览器的内存当中。
假设你刚刚访问了工行网银的页面,并且在工行网银页面中发送了ajax请求,也就是说创建了XMLHttpRequest对象。
那么当你没有关闭浏览器的时候,这个对象还在,此时你正好访问了一些其他的不正规的网站,
如果这些不正规的网站仍然可以无节制的访问工行网银的XMLHttpRequest对象,那将是非常危险的。所以同源策略诞生了。
1、测试:发送ajax请求的时候,是否有跨域问题!!!
在a站点当中发送ajax请求。
访问b站点当中的servlet!!!
A模块代码:ajax1.html
测试ajax请求是否可以跨域访问
B模块请求:HelloServlet.java
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getWriter().print("hello ajax!!!!");
}
}
测试发送请求
可以看到下面报错了,错误信息是:Access to XMLHttpRequest at 'http://localhost:8081/b/hello' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
翻译:访问位于'http://localhost:8081/b/hello'从原点'http://localhost:8080“”已被CORS策略阻止:请求的资源上不存在“Access Control Allow Origin”标头。
测试结果:
使用XMLHttpRequest对象发送ajax请求,进行跨域访问的时候,被“同源策略”阻止。
2、什么是同源策略
同源策略是浏览器的一个策略。是一种安全策略。
也就是说:默认情况下发送ajax请求的时候,只有同源的才能访问,非同源是不允许访问的。
什么是同源?同源有三要素:协议、域名、端口。
只有协议、域名、端口完全一致,才是同源。
以上三要素中任一要素不同,则是非同源。
3、同源策略带来的问题
同源策略是解决了安全的问题。
但是在当下互联网时代,项目的并发量很大,那么项目就一定需要微服务。
而微服务部署在不同的服务器当中,那么这个时候服务和服务之间调用是非常正常的。
那这个时候就需要解决这个跨域的问题了。
五、解决AJAX的XMLHttpRequest对象的跨域问题
方案一:添加响应头(这是一种真正解决跨域的方案)
A站点发送ajax请求访问b站点中的一个Servlet,默认情况下因为同源策略的问题,导致不能跨域访问。
如果B站点中的servlet说了:我允许你访问,你来吧。那就可以了。
A应用:ajax1.html
测试ajax请求是否可以跨域访问
B应用:HelloServlet.java
package com.bjpowernode.javaweb.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应头,允许某个,或者某些站点访问
//response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
response.getWriter().print("hello ajax!!!!");
}
}
测试访问:发现没有出现上面的错误信息,并且能够正常的请求访问
方案二:JSONP方式
JSONP: json with padding(带填充的json),这个名字很诡异,后面再说。
JSONP不是一个真正的ajax请求,或者说他根本就不是一个ajax请求。
只是一个类ajax请求。可以达到跨域访问,同时又可以达到页面局部刷新的效果。
jsonp是一种跨域通信的手段,它的原理其实很简单:
-
首先是利用script标签的src属性来实现跨域。
-
通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。
-
由于使用script标签的src属性,因此只支持get方法
1、执行JS代码
A应用
B应用
package com.bjpowernode.javaweb.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/jsonp1")
public class JSONPServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 向前端浏览器输出一端js脚本代码。
PrintWriter out = response.getWriter();
// 虽然这里是一个字符串,但是这个字符串输出到前端浏览器之后,前端浏览器的script标签会把他当做一端js代码解释并执行。
// 表面上看alert(111)是在java程序中调用了前端,其实这是一种错觉。后端只负责相应一段js代码到前端。
// 真正调用alert(111)代码的还是前端浏览器。
out.print("alert(111)"); // alert是js内置的一个函数的名字。
}
}
执行结果
2、调用JS函数
A应用
B应用
package com.bjpowernode.javaweb.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/jsonp1")
public class JSONPServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 向前端浏览器输出一端js脚本代码。
PrintWriter out = response.getWriter();
// 这里调用的函数是自定义的函数。
out.print("sayHello()");
}
}
执行结果:
3、调用JS函数,传入JSON参数
A应用:
B应用:
@WebServlet("/jsonp1")
public class JSONPServlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 向前端浏览器输出一端js脚本代码。
PrintWriter out = response.getWriter();
// 调用这个sayHello函数的时候能不能传递一个json对象呢
// 在java程序中,你看到的是传递一个json格式的字符串。但是到了前端之后,是一个json对象。
// 将来这里是查询数据库得到的数据,拼接json格式的字符串。
// 获取函数名
String fun = request.getParameter("fun");
out.print(fun + "({\"username\" : \"jackson\"})");
}
}
测试访问:
4、jsonp解决跨域问题,并添加页面局部刷新效果
A应用: