一.跨域问题:
能够正常请求,但是没有办法获取到响应结果
1.设置请求头
response.setHeader("Access-Control-Allow-Origin", "*");
代码如下:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接受数据 String username=request.getParameter("username"); System.out.println("接受的数据:"+username); //接受Ajax传递的数据 //2.响应结果,数据必须为JSON格式 response.getWriter().write("success"); //3.设置请求头 response.setHeader("Access-Control-Allow-Origin", "*"); }
2.JSONP解决跨域问题
普通的跨域访问问题,浏览器会进行拦截,凡是src属性的都不会拦截
ajax:http://localhost:8080/a/AServlet
JSONP实现原理:动态加载<script>标签,利用src属性进行服务器资源的访问,但是只支持Get请求
1.在我们的Ajax请求当中,需要以JSONP方式请求(通过jquery手段,动态生成sript)
jsonp:"代表的时前台传给后台,后台再传递给你 jsonpCallBack"
2.再AJAX请求当中需要将返回的数据格式指定为jsonp
dataType:"JSONP"
3.JSONP需要以Get请求发送 ?username=zhangsan
4.后台需要做的事情:
1.正常接收数据
2.返回数据
前台传递过来的jsonp需要原路返回
String jsonp=request.getP("jsonpCallBack");
需要将返回的数据转换为JSON success
response.getWirter.write(jsonp+"("+返回的数据+")");
修改Ajax请求:
$("#button").click(function () { //获取到文本框的值 var username=$("#username").val(); //发送Ajax请求www.a.com的A工程 $.ajax({ url:"http://www.a.com:8080/a/AServlet?username="+username, type:"GET", jsonp:"jsonpCallBack", //回调函数 dataType:"JSONP", success:function (result) { alert(result); }, error:function () { alert('系统错误~') } }); });
更改后台请求,需要将JSONP原路返回
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接受数据 String username=request.getParameter("username"); System.out.println("接受的数据:"+username); //接受Ajax传递的数据 String jsonpCallBack = request.getParameter("jsonpCallBack"); System.out.println("jsonpCallBack:"+jsonpCallBack); String success = JSON.toJSONString("success"); //2.响应结果,数据必须为JSON格式 response.getWriter().write(jsonpCallBack+"("+success+")"); //3.设置请求头 /*response.setHeader("Access-Control-Allow-Origin", "*");*/ }
3.使用HTTPClient解决:就是不通过浏览器发送请求
B工程的页面发送的Ajax没有办法请求到A工程,因为浏览器会拦截,走后台,后台通过HTTPClient请求请求到A工程,获取到响应结果
1.B工程的Bindex.jsp页面请求到B工程的Servlet
$("#button").click(function () { //获取到文本框的值 var username=$("#username").val(); //发送Ajax请求www.a.com的A工程 $.ajax({ url:"BServlet?username="+username, type:"GET", success:function (result) { alert(result); }, error:function () { alert('系统错误~') } }); });
2.B工程的BServlet去模拟HTTP请求到A工程
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //内部通过HTTPClient进行转发 //构建一个连接 CloseableHttpClient client = HttpClients.createDefault(); //构建请求 HttpGet get=new HttpGet("http://www.a.com:8080/a/AServlet?username="+request.getParameter("username")); //发送请求 CloseableHttpResponse httpResponse = client.execute(get); //获取返回结果 String result = EntityUtils.toString(httpResponse.getEntity()); //将A工程响应结果给页面 response.getWriter().write(result); }
3.A工程处理请求
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.接受数据 String username=request.getParameter("username"); System.out.println("接受的数据:"+username); //2.响应结果 response.getWriter().write("success"); }
2.防止表单重复提交
1.网络延迟,再网络延迟时间内,频繁的提交表单
只能提交一次,监控表单的提交事件,通过一个boolean类型的变量来区分已经点击过还是没有点击,如果已经点击过,表单就不提交,没有点击过再提交
2.重新加载或者后退页面
思路如下:在我访问登录页面的时候,创建一个 Token令牌(当作一个标识) ,保存到session当中,然后再表单提交的时候将令牌一起提交后台Servlet去判断session当中的令牌和表单提交的令牌是否相等,如果相等代表正常提交(session清空),如果不相等,代表非正常提交
Form.jsp页面
<body> <form action="FormServlet" onsubmit="return formSubmit()" method="post"> <input type="hidden" id="hiddenToken" name="formToken"/> <input type="text" name="username"/> <input type="submit" value="提交"/> </form> </body> <script type="text/javascript"> //创建一个变量 false代表没有点击过,true代表已经点击过 var flag=false; function formSubmit() { if(!flag){ //取反值为false flag=true; return true; }else { return false; } } $(function () { //生成令牌 $.ajax({ url:"TokenServlet", type:"POST", success:function (token) { $("#hiddenToken").val(token); } }) }) </script>
TokenServlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //生成令牌 String token = UUID.randomUUID().toString(); //令牌保存到session当中 request.getSession().setAttribute("sessionToken",token); //响应 response.getWriter().write(token); }
FormServlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //验证令牌 //获取页面提交的隐藏域数据 String formToken = request.getParameter("formToken"); //获取Session中的Token String sessionToken = (String)request.getSession().getAttribute("sessionToken"); //如果页面中获取的和session中不一致,代表已经提交过了,不要重复提交 if(!formToken.equals(sessionToken)){ response.getWriter().write("不要重复提交~"); return; } //接收数据 String username = request.getParameter("username"); System.out.println("接收的数据为:"+username); //必须将token清空,不然永远是一致的 request.getSession().removeAttribute("sessionToken"); try { //模拟网络延迟 Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } //返回数据 response.getWriter().write("success"); }
3.防止XSS攻击:
大部分浏览器都已经解决了该问题
脚本注入
防止XSS攻击:后台创建Filter过滤器,过滤所植入的脚本数据<script>,使用正则表达式匹配提交数据的格式