AJAX跨域问题及解决方案

news2025/2/27 21:00:24

文章目录

  • 跨域
    • 哪些方式可以进行跨域
      • 部署服务器
      • 部署模块
        • ajax1
        • ajax2
      • 测试
  • 跨域解决方案
    • 方案1:设置响应头
    • 方案2:jsonp
      • 深入一下jsonp
    • 方案3:代理机制(httpclient)
      • 第一种方案:使用JDK内置的API
      • 第二种方案:使用第三方的开源组件
    • 方案4:nginx反向代理

跨域

跨域是指从一个域名的网页去请求另一个域名的资源。
例如从百度页面点击超链接请求京东的资源。

哪些方式可以进行跨域

我们来测试一下
包括超链接、form表单、JS代码、跨域<script>标签加载JS代码、跨域加载图片、以及AJAX请求

部署服务器

首先建两个服务器,服务器1:HTTP为8080端口,JMX端口为1099,部署ajax1模块,服务器2:HTTP为8081端口,JMX端口为1098,部署ajax2模块
请添加图片描述
服务器1:
请添加图片描述
请添加图片描述
服务器2:
请添加图片描述
请添加图片描述

部署模块

然后ajax1去跨域请求ajax2

ajax1

ajax1 html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax1</title>
</head>
<body>
<!--测试超链接跨域-->
<a href="http://localhost:8081/ajax2">ajax2跨域请求</a><br>
<!--测试form表单跨域-->
<form action="http://localhost:8081/ajax2/user" method="post">
    username:<input type="text" name="username"/><br>
    password:<input type="password" name="password"/><br>
    <input type="submit" value="form跨域"><br>
</form>
<!--测试js代码的跨域-->
<hr>
<button onclick="window.location.href='http://localhost:8081/ajax2'">JS跨域请求</button><br>
<button onclick="document.location.href='http://localhost:8081/ajax2'">JS跨域请求</button><br>
<!--测试使用script跨域加载-->
<script type="text/javascript" src="http://localhost:8081/ajax2/my.js"></script>

<h3>测试跨域加载图片</h3>
<img src="http://localhost:8081/ajax2/img/2.jpg" style="width: 100px">
<hr>
<!--发送AJAX跨域请求,响应到div里面-->
<script type="text/javascript">
    window.onload = function (){
        document.getElementById("btn").onclick = function (){
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function (){
                if (this.readyState == 4) {
                    if (this.status == 200) {
                        document.getElementById("mydiv").innerHTML = this.responseText
                    }
                }
            }
            xhr.open("GET","http://localhost:8081/ajax2/hello",true)
            xhr.send()
        }
    }
</script>
<button id="btn">AJAX跨域请求</button>
<div id="mydiv"></div>
</body>
</html>

ajax2

在ajax2模块,导入图片,以及js代码测试
html页面
请添加图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ajax2</title>
</head>
<body>
<h1>ajax2页面</h1>
</body>
</html>

js代码

alert("js加载了")//页面加载就会弹出

UserServlet用于测试form表单

@WebServlet("/user")
public class UserServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        out.print(username + "," + password);
    }
}

HelloServlet用于测试ajax请求

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("Hello!!!!!");//简单响应
    }
}

测试

  • 1.测试超链接

点击超链接,成功跳转
请添加图片描述

  • 2.测试form表单

输入信息,点击提交,发现成功跳转显示
请添加图片描述
请添加图片描述

  • 3.测试JS代码

点击两个按钮分别是用window和document,发现都成功
请添加图片描述

  • 4.测试跨域加载ajax2的JS代码

正常应该是页面没出来就加载了,发现确实加载了
请添加图片描述

  • 5.测试跨域加载图片

刷新页面,图片加载
请添加图片描述
6.测试ajax跨域请求

点击ajax请求按钮,发现没动静打开F12,发现请求是发过去了
请添加图片描述

请添加图片描述
请添加图片描述

但是报错误:

Access to XMLHttpRequest at 'http://localhost:8081/ajax2/hello' from origin 
'http://localhost:8080' has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

意思是这个请求被CORS策略阻止,并且请求源上不存在“Access Control Allow Origin”标头。
CORS策略阻止:表示这个ajax请求被同源策略阻止
根本原因:在跨域的时候不允许出现XMLHttpRequest对象,因为共享同一个XMLHttpRequest对象是不安全的
同源策略:是浏览器的一种安全策略,指一段脚本只能读取来自同一来源的窗口和文档的属性,同源就是协议、域名和端口都相同。
例如:如果你刚刚在某网银输入账号密码,查看了自己还有账户金额,紧接着又访问一些不规矩的网站,
这些网站可以访问刚刚的网银站点,并且获取账号密码,那后果可想而知。所以,从安全的角度来讲,同源策略是有利于保护网站信息的。
同源的三要素

  • 协议
  • 域名
  • 端口

只有三个要素同时一致,才是同源,否则为不同源

跨域解决方案

现在大部分系统都是大型应用,分布式的微服务的,有一些情况我们是需要使用ajax进行跨域访问的,所以就需要解决跨域的问题

方案1:设置响应头

来源于报错:请求源上不存在“Access Control Allow Origin”标头。
核心原理:跨域访问里的资源允许你跨域访问。
有两种设置方式

response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); // 允许某个,这里允许http://localhost:8080这个源,也就是允许ajax1访问
response.setHeader("Access-Control-Allow-Origin", "*"); // 允许所有

在HelloServlet里设置之后发现响应回来了
请添加图片描述

方案2:jsonp

来源于<script>能够跨域加载JS代码,那能不能加载Servlet呢
在ajax1模块新建个html页面测试一下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp实现跨域</title>
</head>
<body>
<script type="text/javascript" src="http://localhost:8081/ajax2/jsonp"></script>
</body>
</html>

ajax2新建个Servlet

@WebServlet("/jsonp")
public class JsonpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.print("alert('111')");//响应一段JS代码
    }
}

结果:
请添加图片描述
发现<script>是可以加载Servlet的,也就是说到时候响应一段字符串拼接的调用函数,参数是json类型,到时候这个json就是一个业务结果,传过来,让前端调用
例如
html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp实现跨域</title>
</head>

<body>
<script type="text/javascript">
    function sayHello(data){
        alert("hello:" + data.name)
    }
</script>
<script type="text/javascript" src="http://localhost:8081/ajax2/jsonp?fun=sayHello"></script>
</body>
</html>

ajax2响应带json的JS代码

@WebServlet("/jsonp")
public class JsonpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String fun = request.getParameter("fun");
        PrintWriter out = response.getWriter();
        out.print(fun + "({\"name\":\"zhangsan\"})");
    }
}

结果:
请添加图片描述

jsonp:json with padding(带填充的json)

  • jsonp不是一个真正的ajax请求。只不过可以完成ajax的局部刷新效果。可以说jsonp是一种类似ajax请求的机制。
  • 注意:jsonp解决跨域的时候,只支持GET请求。不支持post请求。

深入一下jsonp

我们不希望是页面加载的时候执行,我们需要用户点击按钮的时候刷新局部,怎么办?
我们需要在用户点击按钮的时候把

<script type="text/javascript" src="http://localhost:8081/ajax2/jsonp?fun=sayHello"></script>

这个内容加载到body标签里面
实现
ajax1模块html页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp点击按钮跨域</title>
</head>
<body>
<script type="text/javascript">
    function sayHello(data){
        document.getElementById("mydiv").innerHTML = data.name
    }
    window.onload = function (){
        document.getElementById("btn").onclick = function (){
            //创建script
            const htmlScriptElement = document.createElement("script");//创建script元素
            //设置属性script
            htmlScriptElement.type = "text/javascript"
            htmlScriptElement.src = "http://localhost:8081/ajax2/jsonp?fun=sayHello"
            document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)//将script设置到body里
        }
    }
</script>
<button id="btn">jsonp局部刷新</button>
<div id="mydiv"></div>
</body>
</html>

ajax2模块后端代码

@WebServlet("/jsonp")
public class JsonpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    	//一般这里要连接数据库,这里就不连接了
        String fun = request.getParameter("fun");
        PrintWriter out = response.getWriter();
        out.print(fun + "({\"name\":\"zhangsan\"})");
    }
}

结果:点击按钮,发现ajax2响应了一段JS代码
请添加图片描述
牛人们写的jQuery库,已经对jsonp进行了封装。大家可以直接拿来用。
用之前需要引入jQuery库的js文件。
jQuery中的jsonp其实就是我们方案2的高度封装,底层原理完全相同。
核心代码

$.ajax({
    type : "GET",
    url : "跨域的url",
    dataType : "jsonp", // 指定数据类型
    jsonp : "fun", // 指定参数名(不设置的时候,默认是:"callback")
    jsonpCallback : "sayHello" // 指定回调函数的名字
							   // (不设置的时候,jQuery会自动生成一个随机的回调函数,
    						   //并且这个回调函数还会自动调用success的回调函数。)
})

方案3:代理机制(httpclient)

代理跨域就是当用户点击按钮的时候,发送不跨域的ajax请求,让后端ProxyServlet代理,使用java代码代理发送跨域请求,然后服务器2TargetServlet响应回来的数据是传输给ProxyServlet,通过ProxyServlet代理转响应到前端,避开了跨域。

ajax请求:服务器1按钮->服务器1后端ProxyServlet代理->服务器2TargetServlet
响应:服务器2TargetServlet->服务器1ProxyServlet代理->服务器1前端

Java程序怎么去发送get/post请求呢?

第一种方案:使用JDK内置的API

使用JDK内置的API(java.net.URL…),这些API是可以发送HTTP请求的。

第二种方案:使用第三方的开源组件

比如:apache的httpclient组件。(httpclient组件是开源免费的,可以直接用)

方案4:nginx反向代理

nginx反向代理中也是使用了这种代理机制来完成AJAX的跨域,实现起来非常简单,只要修改一个nginx的配置即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/407721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vite 打包性能优化

Vite 打包性能优化开始一个 Vite ts 项目分包策略gzip 压缩cdn 加速开始一个 Vite ts 项目 这里我们开始了一个 Vite ts 的项目&#xff0c;其中关于 ts 的配置直接看内容注释即可 npm init -y npm i vite -D npm vite-plugin-checker -D #用来强制提示ts报错<!-- inde…

反射时竟然NoSuchMethodException了!看这篇超详细的解决方案吧

前几天九哥在讲Servlet时&#xff0c;为了灵活地使用同一个Servlet来处理对同一张表的业务操作请求&#xff0c;我给学生讲解了BaseServlet工具类的封装&#xff0c;基本实现思路有如下几个步骤。 一. 反射封装BaseServlet工具类 使用反射封装BaseServlet工具类&#xff0c;无…

uview常用组件案例操作及详解(一) 选择器 picker

uview常用组件案例操作及详解&#xff08;一&#xff09; 选择器 picker 1.图片示例 2.使用方法 *为简便代码不提供样式 <view><view><text>行业性质</text><text>*</text></view><view><text v-if"!text.industry…

echarts中的legend属性

legend: {orient: "vertical",right: "0%",top: "15%",icon: "circle", //小圆点itemWidth: 8,itemHeight: 8,itemGap: 15, //间隔formatter: function (params) {let tip1 "";let tip "";let le params.leng…

【uni-app】swiper的使用

最近在学习小程序的开发&#xff0c;其中有用到swiper&#xff0c;在这里记录一下我的学习历程 有一些人&#xff0c;他刚开始并不会开发小程序&#xff0c;但是在任务面前&#xff0c;没有什么是不可以学的… 刚开始接触到swiper的时候&#xff0c;是在uni-app的官方文档里&am…

Vue中的Pinia状态管理工具 | 一篇文章教会你全部使用细节

文章目录Pinia状态管理Pinia和Vuex的对比Pinia基本使用&#x1f364;创建Pinia&#x1f364;创建StorePinia核心概念State&#x1f35f;state基本使用&#x1f35f;state其他操作Pinia核心Getters&#x1f355;getters基本使用&#x1f355;getters其他操作Pinia核心Actions&am…

React -- useState 的使用及注意事项

一、基本使用 useState是 react 提供的一个定义响应式变量的 hook 函数&#xff0c;基本语法如下&#xff1a; const [count, setCount] useState(initialCount)它返回一个状态和一个修改状态的方法&#xff0c;状态需要通过这个方法来进行修改&#xff1b;initialCount 是我…

Vue3+Vite实现动态路由

项目基本目录 1.首先定义初始默认的路由routes(router.js文件),vue文件使用import引入可以按需加载 import {createRouter,createWebHashHistory } from "vue-router";import store from ../store/index.jsconst routes [{path: "/login",component: () …

jsjiami.com V6版本,js解密的方法。

我们在爬内容&#xff0c;抓取页面的时候&#xff0c;总会遇到sojson v5&#xff0c;jsjiami.com的v6加密。 jsjiami v6 &#xff1a; JS加密,JS不可逆加密,JS混淆,JS混淆加密,JS压缩加密 - [JavaScript加密] 我看了下这个js完全有效。废话不多说。直接上代码。 (function (…

vue中深度选择器

scoped的作用 scoped 可以使当前的样式只在自己当前的组件内起作用。为了防止在一个组件内引入了子组件&#xff0c;而子组件没有加scoped。这个时候如果父子组件有相同的类名&#xff0c;就会产生样式的影响。 原理: 加了scoped就相当于给当前组件所有的标签添加一个【data-v-…

微信小程序实现轮播图

实现轮播图之前必须知道以下三点&#xff1a; 一、轮播图外层容器swiper 二、每一个轮播项swiper-item 三、swiper标签存在默认样式 1. width 100% 2. height 默认为 150px 3 .swiper高度无法实现由内容撑开 默认的150px高度的轮播图如下图: 原图是长这个样子的&#xf…

bootstrap-fileinput(二:编辑(修改)界面文件的上传,回显,删除(数据库同时删除)的操作 )

文章目录bootstrap-fileinput(二&#xff1a;编辑(修改)界面文件的上传&#xff0c;回显&#xff0c;删除(数据库同时删除)的操作 )一、编辑界面文件的上传二、编辑界面文件的回显1.文件的实体类&#xff1a;2.想要回显文件&#xff0c;首先要在工程类(你的编辑界面的主类)里面…

ES6面试问题汇总

面试官通过总问题&#xff0c;ES6方法开始提问 1.ES6有哪些新增方法&#xff1f;/你了解哪些ES6方法&#xff1f;&#xff08;总问题&#xff09; 块级作用域、 模板字符串、 解构赋值、 箭头函数、 函数默认参数、 剩余参数&运算符、 set和map、 import和exprot用…

Vue中实现过渡动画

文章目录Vue的transition动画Transition动画的使用Transition组件的原理Transition动画的classVue的animation动画Animation动画的使用同时设置两种动画(了解)过渡的模式mode列表过渡列表过渡的介绍列表过渡的使用Vue的transition动画 Transition动画的使用 在开发中&#xf…

vite配置cdn优化打包体积

文章目录前言一、版本确认二、使用步骤1.rollup-plugin-visualizer打包体积可视化面板2.配置cdn方法第一种方法&#xff1a; vite-plugin-cdn-import第二种方法&#xff1a; rollup-plugin-external-globals总结前言 大家都知道前端性能优化的方法&#xff0c;cdn外部引入的方…

【微信小程序】小程序知识补充篇

&#x1f381;写在前面&#xff1a; 观众老爷们好呀&#xff0c;这里是前端小刘不怕牛牛频道&#xff0c;小程序系列又更新了呀。 还有就是中秋节就快来啦&#xff0c;程序员过中秋&#xff0c;当然是要好好放松一下啦&#xff0c;那么中秋前我们就不能偷懒了&#xff0c;赶紧学…

Controller层接收前端传参的几种方法。@RequestParam、@RequestBody、@PathVariable。及参数校验。

一、RequestParam 主要用于将请求参数区域的数据映射到控制层方法的参数上 // http://localhost:8080/wh/user/edit?Id9452659856325148452&name天天向上// RequestParam源码Target({ElementType.PARAMETER}) // 只能作用于参数上 Retention(RetentionPolicy.RUNTIME) D…

vue watch监听数据解决新旧值一样的问题(newValue, oldValue)

watch是监听 Vue 实例变化的一个表达式或方法。回调函数得到的参数为新值和旧值。 基础用法 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge…

异步函数async

什么是同步异步 在最新的ES7&#xff08;ES2017&#xff09;中提出的前端异步特性&#xff1a;async、await。 在了解async和await之前得先明白什么是同步函数&#xff0c;什么是异步函数。 同步函数&#xff1a;当一个函数是同步执行时&#xff0c;那么当该函数被调用时不会…

前端CryptoJS和Java后端数据互相加解密(AES)

目录一、序言二、关于前端CryptoJS1、CryptoJS简单介绍2、加密和填充模式选择3、前端AES加解密示例(1) cryptoutils工具类(2) 测试用例(3) 加解密后输出内容说明三、Java后端AES加解密1、Java中支持的加密模式和填充说明2、工具类CryptoUtils3、测试用例一、序言 最近刚好在做…