【JS】AJAX跨域-JSONP解决方案(一)
AJAX跨域介绍
AJAX 跨域访问是用户访问A网站时所产生的对B网站的跨域访问请求均提交到A网站的指定页面
由于安全方面的原因, 客户端js使用xmlhttprequest只能用来向来源网站发送请求,比如在www.readlog.cn下去请求test.readlog.cn的数据,都是不行的。
什么是AJAX跨域问题
- 简单来说,就是前端调用后端服务接口时
- 如果服务接口不是同一个域,就会产生跨域问题
AJAX跨域场景
- 前后端分离、服务化的开发模式
- 前后端开发独立,前端需要大量调用后端接口的场景
- 只要后端接口不是同一个域,就会产生跨域问题
- 跨域问题很普遍,解决跨域问题也很重要
AJAX跨域原因
- 浏览器限制:浏览器安全校验限制
- 跨域(协议、域名、端口任何一个不一样都会认为是跨域)
- XHR(XMLHttpRequest)请求
AJAX跨域问题解决思路
- 浏览器:浏览器取下跨域校验,实际价值不大
- XHR:不使用XHR,使用JSONP,有很多弊端,无法满足现在的开发要求
- 跨域:被调用方修改支持跨域调用(指定参数);调用方修改隐藏跨域(基于代理)
如图:
解决跨域问题
实例
1、新建一个SpringMVC的Maven工程,参考:【Maven】Eclipse 使用Maven创建SpringMVC Web项目,pom.xml文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test</groupId>
<artifactId>test-ajax-cross</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<!-- 定义maven变量 -->
<properties>
<!-- spring -->
<spring.version>4.2.0.RELEASE</spring.version> <!-- log -->
<commons-logging.version>1.1.3</commons-logging.version> <!-- Servlet -->
<servlet.version>3.0.1</servlet.version>
<jsp-api.version>2.2</jsp-api.version> <!-- jstl -->
<jstl.version>1.2</jstl.version>
<standard.version>1.1.2</standard.version> <!-- Tool -->
<!-- jackson json包 -->
<jackson-databind.version>2.9.7</jackson-databind.version>
<jackson-core.version>2.9.7</jackson-core.version>
<jackson-annotations.version>2.9.7</jackson-annotations.version> <!-- test -->
<junit.version>3.8.1</junit.version> <!-- jdk -->
<jdk.version>1.8</jdk.version>
<maven.compiler.plugin.version>2.3.2</maven.compiler.plugin.version>
</properties> <dependencies> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency> <!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>${jsp-api.version}</version>
<scope>provided</scope>
</dependency> <!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency> <dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>${standard.version}</version>
</dependency> <!-- jackson json包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson-core.version}</version>
</dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson-annotations.version}</version>
</dependency> <!-- test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency> </dependencies> <build>
<plugins>
<!-- define the project compile level -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.compiler.plugin.version}</version>
<configuration>
<source>${jdk.version}</source>
<target>${jdk.version}</target>
</configuration>
</plugin>
</plugins>
<finalName>test-ajax-cross</finalName>
</build> </project>
2、新建一个测试controller,注意返回的是一个json对象,项目中需要加入json依赖
package com.test.ajax.cross.controller; import java.util.HashMap;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView; @Controller
@RequestMapping("/test")
public class TestController { @RequestMapping(value="/get")
@ResponseBody
public Map getTest(HttpServletRequest request){
Map<String, Object> map = new HashMap();
map.put("data", "TestController getTest()");
return map;
}
}
3、新建一个测试界面webapp/static/test.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="jquery-1.11.3.min.js" type="text/javascript"></script>
</head>
<body>
<h2>测试界面</h2>
<a href="#" onclick="get()">发送get请求</a>
</body>
<script type="text/javascript">
function get(){
$.getJSON("http://localhost:8080/test-ajax-cross/test/get").then(function(result){
console.log(result);
$("body").append("<br>" + JSON.stringify(result));
});
}
</script>
</html>
4、将项目发布到Tomcat中,并访问测试界面,http://localhost:8080/test-ajax-cross/static/test.html
5、修改hosts文件(用来映射域名与IP),将a.com映射到127.0.0.1,在使用地址:http://a.com:8080/test-ajax-cross/static/test.html#,访问,可以看到无法完成ajax请求了
解决方案一(禁止浏览器检查)
禁止浏览器检查,启动浏览器时,添加参数禁止浏览器对ajax做检查
windows采用以下方式打开谷歌浏览器
"C:\Users\UserName\AppData\Local\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir
//不知道chrome.exe 地址的话
右键chrome图标-->属性-->如下图-->图中 目标 就是文件的位置了,直接复制出来即可
mac采用以下方式打开谷歌浏览器
//chrome 浏览器
open -a "Google Chrome" --args --disable-web-security --user-data-dir
//safari 浏览器
open -a '/Applications/Safari.app' --args --disable-web-security --user-data-dir
输入地址:http://localhost:8080/test-ajax-cross/static/test.html#,进行访问,可以看到能正常完成ajax请求了
解决方案二(使用JSONP)
Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站)那获取资料,即跨域读取数据。
JSONP的基本思想是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来
当通过<script>元素调用数据时,响应内容必须用javascript函数名和圆括号包裹起来。而不是发送这样一段JSON数据,这就是JSONP中P的意义所在
在实践中,支持JSONP的服务不会强制指定客户端必须实现的回调函数名称,比如handleResponse。相反,它们使用査询参数的值,允许客户端指定一个函数名,然后使用函数名去填充响应。许多支持JSONP的服务都能分辨出这个参数名。另一个常见的参数名称是callback,为了让使用到的服务支持类似特殊的需求,就需要在代码上做一些修改了
JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的JSON数据
1、修改Java后台TestController类,增加jsonp的响应返回
package com.test.ajax.cross.controller; import java.util.HashMap;
import java.util.Map; import javax.servlet.http.HttpServletRequest; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; @Controller
@RequestMapping("/test")
public class TestController { private ObjectMapper objectMapper = new ObjectMapper(); @RequestMapping(value="/get")
@ResponseBody
public Map getTest(HttpServletRequest request){
Map<String, Object> map = new HashMap();
map.put("data", "TestController getTest()");
return map;
} @RequestMapping(value="/getJsonp")
@ResponseBody
public String getJsonp(HttpServletRequest request) throws JsonProcessingException{
// 与前端约定好回调方法名称,默认是callback
String callback = request.getParameter("callback");
Map<String, Object> map = new HashMap();
map.put("data", "TestController getTest()");
String ret = callback+"("+ objectMapper.writeValueAsString(map)+")";
return ret;
}
}
2、新建一个测试界面webapp/static/test2.html,用于jsonp请求,
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="jquery-1.11.3.min.js" type="text/javascript"></script>
</head>
<body>
<h2>测试jsonp界面</h2>
<a href="#" onclick="get()">发送get请求</a>
</body>
<script type="text/javascript">
function get(){ $.ajax({
url: "http://localhost:8080/test-ajax-cross/test/getJsonp",
dataType: "jsonp",
jsonp:"callback", // 默认值是callback,可以修改
success: function (result) {
console.log(result);
$("body").append("<br>" + JSON.stringify(result));
}
});
}
</script>
</html>
3、浏览器中输入地址:http://a.com:8080/test-ajax-cross/static/test2.html#,进行访问
观察:使用F12查看请求
参数callback对应的值是,请求响应后的回调方法
参数_作用,值是随机数,为了是请求不使用缓存
返回内容是:jQuery111306019926935268467_1567783875359({"data":"TestController getTest()"})
注意:JSONP的弊端
- 服务器需要改动代码支持
- 只支持GET
- 发送的不是XHR请求
【JS】AJAX跨域-JSONP解决方案(一)的更多相关文章
- JS Ajax跨域访问
js ajax跨域访问报"No 'Access-Control-Allow-Origin' header is present on the requested resource 如果请求的 ...
- Ajax进阶之原生js与跨域jsonp
什么是Ajax? 两个数求和: 用Jquery和数据用json格式 viws函数: from django.shortcuts import render,HttpResponse # Create ...
- ajax跨域请求解决方案
大家好,今天我们学习了js的跨域请求的解决方案,由于JS中存在同源策略,当请求不同协议名,不同端口号.不同主机名下面的文件时,将会违背同源策略,无法请求成功!需要进行跨域处理! 方案一.后台PHP进行 ...
- java、ajax 跨域请求解决方案('Access-Control-Allow-Origin' header is present on the requested resource. Origin '请求源' is therefore not allowed access.)
1.情景展示 ajax调取java服务器请求报错 报错信息如下: 'Access-Control-Allow-Origin' header is present on the requested ...
- jQuery的ajax跨域 Jsonp原理
1.Jsonp Jsonp(json with padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题. Jsonp是为了解决ajax跨域发送http请求出现的,利用S ...
- ajax跨域问题解决方案
今天来记录一下关于ajax跨域的一些问题.以备不时之需. 跨域 同源策略限制 同源策略阻止从一个域上加载的脚本获取或操作另一个域上的文档属性.也就是说,受到请求的 URL 的域必须与当前 Web 页面 ...
- AJAX 跨域 CORS 解决方案
本篇文章由:http://xinpure.com/solutions-for-cross-domain-ajax-cors/ 两种跨域方法 在 Javascript 中跨域访问是比较常见的事情 就像现 ...
- ajax跨域问题解决方案(jsonp,cors)
跨域 跨域有三个条件,满足任何一个条件就是跨域 1:服务器端口不一致 2:协议不一致 3:域名不一致 解决方案: 1.jsonp 在远程服务器上设法动态的把数据装进js格式的文本代码段中,供客户端调用 ...
- PHP下ajax跨域的解决方案之jsonp
首先要说明一下json和jsonp的区别? json是一种基于文本的数据交换方式,或者叫做描述数据的一种格式. var person = { "name": "test& ...
随机推荐
- C语言开发具有可变长参数的函数的方法
学习交流可加 微信读者交流①群 (添加微信:coderAllen) 程序员技术QQ交流①群:736386324 --- 前提:ANSI C 为了提高可移植性, 通过头文件stdarg.h提供了一组方便 ...
- Layui外部js修改表格内容
//测试修改数据的方法! var _tds=$(".layui-table-body.layui-table-main:eq(1) tr:eq(1)").children(); _ ...
- memcached——学习
文章:memcached 常用命令及使用说明 远程清除memcached缓存 使用命令行: telnet 127.0.0.1 11211 连上memcached 然后使用命令:flush_all ...
- Kotlin反射实践操作详解
继续对反射进行实战. 获取构造方法: 先定义一个主构造方法,2个次构造方法,接下来咱们用反射来获取一下构造方法: 其结果: [fun <init>(kotlin.Int, kotlin.S ...
- 软帝学院:java多线程知识点分享
1.进程和线程: 进程:正在进行的程序.每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元. 线程:进程内部的一条执行路径或者一个控制单元. 两者的区别: 一个进程至少有一个线程 ...
- 为什么管理人员都喜欢用Visio画图
一.形状数据一体化 这是管理者最喜欢的功能了,这也Visio的最核心的功能: 操作如下: 例如流程中的步骤.开始日期或结束日期.成本.设备部件等.数字.图标.颜色.标志和进度条等图形有助于快速方便地浏 ...
- pandas 常用方法使用示例
from pandas import DataFrame import numpy as np import pandas as pd t={ , , np.nan, , np.nan, ], &qu ...
- npm中的学习课程
我也不知道叫什么名字好 进入 https://nodeschool.io/zh-cn/,你能够看到许多课程. 这些课程大多面向零基础的,非常有趣(类似于许多关卡的小游戏). 快速开始 首先,确定你的电 ...
- JavaScript基础02-条件语句及介绍函数
条件语句 if 和 if - else 语句 if(你还没睡着么?){ 是 那我们去撸串--- } 当条件判断为真true时,执行花括号内的语句,如果条件为假false,跳过花括号内的语句 if ...
- mariadb(mysql)[详解]
本文链接:https://blog.csdn.net/root__oo7/article/details/82817501 安装: [root@bogon ~]# yum install mariad ...