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

Servlet中跨域问题详解

三、可以跨域的请求

1、在哪些请求的情况下,跨域没有问题呢?

  1. 超链接
  2. form表单
  3. window.location.href
  4. document.location.href
  5. img: src属性
  6. 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、超连接

Servlet中跨域问题详解

2、form表单

Servlet中跨域问题详解

3、测试以下四种的跨域访问

window.location.href
document.location.href
img: src属性
script: src属性

Servlet中跨域问题详解

四、不可以跨域的请求

使用 XMLHttpRequest对象发送AJAX请求的时候不能跨域!!!

为什么使用XMLHttpRequest对象发送AJAX请求不能跨域呢?

  • XMLHttpRequest是浏览器内置的对象。(javascript内置的对象)
  • XMLHttpRequest对象一旦创建之后会一直存储在浏览器的内存当中。

假设你刚刚访问了工行网银的页面,并且在工行网银页面中发送了ajax请求,也就是说创建了XMLHttpRequest对象。

那么当你没有关闭浏览器的时候,这个对象还在,此时你正好访问了一些其他的不正规的网站,

如果这些不正规的网站仍然可以无节制的访问工行网银的XMLHttpRequest对象,那将是非常危险的。所以同源策略诞生了。

1、测试:发送ajax请求的时候,是否有跨域问题!!!

在a站点当中发送ajax请求。
访问b站点当中的servlet!!!

A模块代码:ajax1.html

javascript;gutter:true; 测试ajax请求是否可以跨域访问</p> <pre><code>// ES6的新特性:箭头函数(不知道的下去可以研究一下。) window.onload = () => { // 页面加载完毕之后,执行回调函数 // 给按钮绑定鼠标单击事件 document.getElementById("btn").onclick = () => { // 发送ajax请求 // 1. 创建ajax核心对象 let xmlHttpRequest = new XMLHttpRequest(); // let关键字可以声明js变量。和var差不多。都是关键字。但是有区别。 // 2. 注册回调函数 xmlHttpRequest.onreadystatechange = () => { /*对象状态值,0—未初始化 1—正在加载 2—加载完毕 3—交互 4—完成。*/ if (xmlHttpRequest.readyState === 4) { if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status < 300) { document.getElementById("mydiv").innerHTML = xmlHttpRequest.responseText } } } // 3. 开启通道 xmlHttpRequest.open("GET", "http://localhost:8081/b/hello", true) // 4. 发送请求 xmlHttpRequest.send() } } </code></pre> <p>发送ajax跨域请求</p> <pre><code> > B模块请求:HelloServlet.java ;gutter:true;
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请求,进行跨域访问的时候,被” 同源策略“阻止。

Servlet中跨域问题详解

2、什么是同源策略

同源策略是浏览器的一个策略。是一种安全策略。
也就是说:默认情况下发送ajax请求的时候,只有同源的才能访问,非同源是不允许访问的。
什么是同源?同源有三要素: 协议、域名、端口。
只有协议、域名、端口完全一致,才是同源。
以上三要素中任一要素不同,则是非同源。

Servlet中跨域问题详解

3、同源策略带来的问题

同源策略是解决了安全的问题。
但是在当下互联网时代,项目的并发量很大,那么项目就一定需要微服务。
而微服务部署在不同的服务器当中,那么这个时候服务和服务之间调用是非常正常的。
那这个时候就需要解决这个跨域的问题了。

五、解决AJAX的XMLHttpRequest对象的跨域问题

方案一:添加响应头(这是一种真正解决跨域的方案)

A站点发送ajax请求访问b站点中的一个Servlet,默认情况下因为同源策略的问题,导致不能跨域访问。
如果B站点中的servlet说了:我允许你访问,你来吧。那就可以了。

A应用:ajax1.html



    
    测试ajax请求是否可以跨域访问











B应用:HelloServlet.java

java;gutter:true; package com.bjpowernode.javaweb.servlet;</p> <p>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;</p> <p>@WebServlet("/hello") public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {</p> <pre><code> // 设置响应头,允许某个,或者某些站点访问 //response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); response.getWriter().print("hello ajax!!!!"); } </code></pre> <p>}</p> <pre><code> > 测试访问:发现没有出现上面的错误信息,并且能够正常的请求访问 ![Servlet中跨域问题详解](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230605/2126720-20220620143557815-1385916725.gif) ### 方案二:JSONP方式 JSONP: json with padding(带填充的json),这个名字很诡异,后面再说。 JSONP不是一个真正的ajax请求,或者说他根本就不是一个ajax请求。 只是一个类ajax请求。可以达到跨域访问,同时又可以达到页面局部刷新的效果。 jsonp是一种跨域通信的手段,它的原理其实很简单: 1. 首先是利用script标签的src属性来实现跨域。 2. 通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。 3. 由于使用script标签的src属性,因此只支持get方法 > 1、执行JS代码 A应用 B应用 ;gutter:true;
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内置的一个函数的名字。
}
}

执行结果

Servlet中跨域问题详解

2、调用JS函数

A应用


B应用

java;gutter:true; package com.bjpowernode.javaweb.servlet;</p> <p>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;</p> <p>@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()"); } }</p> <pre><code> 执行结果: ![Servlet中跨域问题详解](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230605/2126720-20220620145447655-2131706619.png) > 3、调用JS函数,传入JSON参数 A应用: <pre><script> <span>//</span><span> 自定义一个函数</span> <span>//</span><span> 不但可以跨域,而且还可以完成前后端的交互。</span> <span>function</span> sayHello(data){ <span>//</span><span> data只是一个变量名,随意的。愿意写什么就写什么。data是一个变量,接受json数据的。</span> alert("hello " +<span> data.username) } </span></script> <script></script></pre> B应用: ;gutter:true;
@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\"})");
}
}

测试访问:

Servlet中跨域问题详解

4、jsonp解决跨域问题,并添加页面局部刷新效果

A应用:






B应用:

java;gutter:true; @WebServlet("/jsonp2") public class JSONPServlet2 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {</p> <pre><code> // 获取函数名 String fun = request.getParameter("fun"); // 响应js脚本 response.getWriter().print(fun + "({\"username\":\"zhangsan\"})"); } </code></pre> <p>}</p> <pre><code> 测试访问: ![Servlet中跨域问题详解](https://johngo-pic.oss-cn-beijing.aliyuncs.com/articles/20230605/2126720-20220620151402149-1804966310.png) ### 方案三:jQuery提供的JSONP方式 jQuery的JSONP实现方式和方案二一模一样。 jQuery就是对以上的JSONP进行了封装。 外面伪装了一个AJAX请求。实际上根本不是AJAX请求。 A应用: <pre><!DOCTYPE html> <html> <head> <meta> <title>jQuery封装的JSONP</title> </head> <body> <!--引入jQuery库--> <script></script> <script> <span>function</span><span> setDiv(data){ $(</span>"#mydiv"<span>).html(data.username) } </span></script> <script> <span>//</span><span> 这个请求是jQuery底层发送的请求:/b/jsonp2?fun=setDiv&_=1655647292689</span> <span>//</span><span> 添加时间戳是为了解决get缓存问题。</span> $(<span>function</span><span>(){ $(</span>"#btn").click(<span>function</span><span> (){ </span><span>//</span><span> 发送ajax跨域请求(JSONP方式,底层根本不是ajax请求)</span> <span> $.ajax({ type : </span>"get"<span>, url : </span>"http://localhost:8081/b/jsonp2"<span>, dataType : </span>"jsonp", <span>//</span><span> 数据类型</span> jsonp : "fun", <span>//</span><span>参数名字</span> jsonpCallback : "setDiv" <span>//</span><span> 回调函数的名字</span> <span> }) }) }) </span></script> <button>jQuery的JSONP实现跨域</button> </body> </html></pre> B应用: ;gutter:true;
@WebServlet("/jsonp2")
public class JSONPServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

// 获取函数名
String fun = request.getParameter("fun");
// 响应js脚本
response.getWriter().print(fun + "({\"username\":\"zhangsan\"})");
}
}

测试结果:

Servlet中跨域问题详解

方案四:使用代理机制

在java程序中使用httpclient组件。

Servlet中跨域问题详解

方案五:使用nginx反向代理

Original: https://www.cnblogs.com/zhangzhixi/p/16392755.html
Author: Java小白的搬砖路
Title: Servlet中跨域问题详解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/612242/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 太赞了!墙裂推荐这款网页版 Nginx 配置生成器,好用到爆!

    之前民工哥也给大家介绍过一款Nginx配置生成器:强大!Nginx 配置在线一键生成”神器”,不太了解的人可以去看一看。 最近民工哥又发现一款好用的网页版开…

    数据库 2023年6月9日
    0160
  • JWT简介

    JWT简介 在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token认证机制。 (1) 什…

    数据库 2023年6月14日
    094
  • zabbix监控配置项配置

    1.手动添加监控项 2. 使用模板添加监控项 3.0 邮件告警 创建主机并加入主机组 1.手动添加监控项 即获取数据的监控指标增加用户,修改用户,删除用户etc/passwd文件都…

    数据库 2023年6月14日
    082
  • 版本控制gitlab

    版本控制gitlab 版本控制gitlab 什么是版本控制gitlab gitlab部署 什么是版本控制gitlab GitLab 是一个用于仓库管理系统的开源项目,使用Git作为…

    数据库 2023年6月14日
    078
  • Host-Only模式下虚拟机无法联网问题

    环境: 镜像:Linux CentOS7——————————…

    数据库 2023年6月11日
    080
  • Idea新建一个springboot的项目

    1、 2、 3、 4、 5、新建yml文件 6、如果没有这个yml文件没有变成绿叶标的话 如下操作添加即可 一般过一会就好了 Original: https://www.cnblo…

    数据库 2023年6月9日
    087
  • django中的JsonRseponse对象

    json格式的数据 在进行前后端数据交互的时候,我们需要使用json格式的数据作为过渡,实现跨语言传输数据! django中的JsonResponse对象 在django中Json…

    数据库 2023年6月14日
    077
  • 工厂模式

    工厂模式是java中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一…

    数据库 2023年6月11日
    082
  • 1_Html

    一. 引言 1.1 HTML概念 网页, 是网站中的一个页面, 是构成网站的基本元素, 是承载各种网站应用的平台. 通俗的说, 网站就是由网页组成的, 通常我们看到的网页都是以ht…

    数据库 2023年6月11日
    064
  • 4、异常

    一、异常的体系结构: java.lang.Throwable |—–java.lang.Error:一般不编写针对性的代码进行处理。 |—&#8…

    数据库 2023年6月6日
    085
  • 分库分表真的适合你的系统吗?聊聊分库分表和NewSQL如何选择

    曾几何时,”并发高就分库,数据大就分表”已经成了处理 MySQL 数据增长问题的圣经。 面试官喜欢问,博主喜欢写,候选人也喜欢背,似乎已经形成了一个闭环。 …

    数据库 2023年6月16日
    084
  • 设计 | ClickHouse 分布式表实现数据同步

    作者:吴帆 青云数据库团队成员主要负责维护 MySQL 及 ClickHouse 产品开发,擅长故障分析,性能优化。 在多副本分布式 ClickHouse 集群中,通常需要使用 D…

    数据库 2023年5月24日
    093
  • django中的视图层

    1.什么是视图层 简单来说,就是用来接收路由层传来的请求,从而做出相应的响应返回给浏览器 2.视图层的格式与参数说明 2.1基本格式 from django.http import…

    数据库 2023年6月14日
    062
  • mysql常用操作汇总

    工作中经常用会遇到这种情况,可以访问mysql所在的服务器,但是服务器端口不对外暴露(通常因为安全原因)。这时,操作数据库只能通过命令行和 mysql client窗口来实现。我对…

    数据库 2023年5月24日
    069
  • 设计模式之(3)——抽象工厂方法模式

    定义:抽象工厂模式简单地讲,就是提供一个超级工厂,围绕这个超级工厂创建其他工厂;抽象工厂模式提供一个创建一些列相关或者相互依赖对象的接口; 在此之前我们先来讲一下产品等级和产品族的…

    数据库 2023年6月14日
    068
  • Word书签替换,加盖电子印章及转换PDF(Java实用版)

    一、前言 在项目中有需要对word进行操作的,可以看看哈,本次使用比较强大的spire组件来对word进行操作,免费版支持三页哦,对于不止三页的word文件,可以购买收费版,官网:…

    数据库 2023年6月16日
    079
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球