JsonP------实现跨域请求

2020-07-25 23:57:30 浏览数 (1)

JsonP技术

  • 介绍
    • JsonP
    • 跨域
    • 同源策略
    • 非同源限制以下行为
    • 常见的跨域场景
    • 跨域的解决方案
    • JsonP的优缺点
  • Json的使用
    • 搭建应用场景
    • JsonP实现手动跨域
      • jsonDemo1的jsp页面(发送跨域请求)
      • jsonDemo2的controller
      • JsonUtils工具类(需要添加相关坐标jackson-databind)
    • 实现自动跨域(SpringMVC对JsonP的支持)
      • jsonDemo1的jsp页面同上
      • jsonDemo2的controller

介绍

JsonP

Jsonp(JSON with Padding) 是 json 的一种"使用模式",可以让网页从别的域名(网站) 那获取资料,即跨域读取数据。 为什么我们从不同的域(网站)访问数据需要一个特殊的技术(JSONP )呢?这是因为同源策略。

跨域

跨域是指一个域(网站)下的文档或脚本试图去请求另一个域(网站)下的资源。

同源策略

同源策略/SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器, 它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSS、CSFR 等攻击。所谓同源是指"协议 域名 端口"三者相同,即便两个不同的域名指向同一个 ip 地址,也非同源。

非同源限制以下行为

1.) Cookie、LocalStorage 和 IndexDB 无法读取 2.) DOM 和 Js 对象无法获得 3.) AJAX 请求不能发送

常见的跨域场景

URL

说明

是否允许通信

http://www.domain.com/a.js http://www.domain.com/b.js http://www.domain.com/lab/c.js

同一域名,不同文件或路径

允许

http://www.domain.com:8000/a.js http://www.domain.com/b.js

同一域名,不同端口

不允许

http://www.domain.com/a.js https://www.domain.com/b.js

同一域名,不同协议

不允许

http://www.domain.com/a.js http://192.168.4.12/b.js

域名和域名对应相同 ip

不允许

http://www.domain.com/a.js http://x.domain.com/b.jshttp://domain.com/c.js

主域相同,子域不同

不允许

http://www.domain1.com/a.js http://www.domain2.com/b.js

不同域名

不允许

跨域的解决方案

1) 通过 jsonp 跨域 2) document.domain iframe 跨域 3) location.hash iframe 4) window.name iframe 跨域 5) postMessage 跨域 6) 跨域资源共享(CORS) 7) nginx 代理跨域 8) nodejs 中间件代理跨域 9) WebSocket 协议跨域

JsonP的优缺点

JSONP 的优点是:它不像 XMLHttpRequest 对象实现的 Ajax 请求那样受到同源策略的 限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要 XMLHttpRequest 或 ActiveX 的支持;并且在请求完毕后可以通过调用 callback 的方式回传结果。

JSONP 的缺点则是:它只支持 GET 请求而不支持 POST 等其它类型的 HTTP 请求;它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面之间如何进行 JavaScript 调用 的问题。

Json的使用

搭建应用场景

0 )创建parent项目 ,规定jar和版本控制 1)创建两个 war项目,名称为 jsonDemo1(8080)、jsonDemo2(9090) 2)jsonDemo1 中提供一个 index.jsp ,用于进行跨域访问( 只需配置最简单的web.xml以及一个用于发送的jsp页面 ) 3)在 jsonDemo1 的 index.jsp 中通过 Jquery 的 Ajax 跨域请求 jsonDemo2 4)jsonDemo2 中使用 springMVC 处理请求,返回一个 json 对象 ,添加jsonutils 工具包 5)在 jsonDemo1 中将返回的结果插入到 index.jsp 中

项目框架: parent/pom.xml

代码语言:javascript复制
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.bjsxt</groupId>
	<artifactId>parent</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<!-- 对依赖的jar包的版本统一进行定义 -->
	<properties>
		<activemq.version>5.9.0</activemq.version>
		<xbean.version>4.5</xbean.version>
		<jms.version>4.1.6.RELEASE</jms.version>
		<activemq-pool.version>5.9.0</activemq-pool.version>
		<solrj.version>4.10.3</solrj.version>
		<jedis.version>2.9.0</jedis.version>
		<junit.version>4.12</junit.version>
		<spring.version>4.1.3.RELEASE</spring.version>
		<mybatis.version>3.2.8</mybatis.version>
		<mybatis.spring.version>1.2.2</mybatis.spring.version>
		<mysql.version>5.1.32</mysql.version>
		<slf4j.version>1.6.4</slf4j.version>
		<druid.version>1.0.9</druid.version>
		<jstl.version>1.2</jstl.version>
		<servlet-api.version>2.5</servlet-api.version>
		<tomcat.version>2.2</tomcat.version>
		<jsp-api.version>2.0</jsp-api.version>
		<zkClient-version>0.10</zkClient-version>
		<dubbo-version>2.5.4</dubbo-version>
		<jackson.version>2.4.2</jackson.version>
		<commons-net.version>3.3</commons-net.version>
		<commons-fileupload.version>1.3.1</commons-fileupload.version>
	</properties>


	<!-- jar包的依赖注入 ,由于该工程是一个父工程,所以jar包在该pom文件中只是声明 -->
	<dependencyManagement>
		<dependencies>
		<!-- ActiveMQ客户端完整jar包依赖 -->
		<dependency>
			<groupId>org.apache.activemq</groupId>
			<artifactId>activemq-all</artifactId>
			<version>${activemq.version}</version>
		</dependency>
		<!-- ActiveMQ和Spring整合配置文件标签处理jar包依赖 -->
		<dependency>
			<groupId>org.apache.xbean</groupId>
			<artifactId>xbean-spring</artifactId>
			<version>${xbean.version}</version>
		</dependency>
		<!-- Spring-JMS插件相关jar包依赖 -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jms</artifactId>
			<version>${jms.version}</version>
		</dependency>
		<!-- Spring-JMS插件相关jar包依赖 -->
		<dependency>
		    <groupId>org.apache.activemq</groupId>
		    <artifactId>activemq-pool</artifactId>
		    <version>${activemq-pool.version}</version>
		</dependency>
		<dependency>
		    <groupId>org.apache.activemq</groupId>
		    <artifactId>activemq-jms-pool</artifactId>
		    <version>${activemq-pool.version}</version>
		</dependency>
		
		<dependency>
			<groupId>org.apache.solr</groupId>
			<artifactId>solr-solrj</artifactId>
			<version>${solrj.version}</version>
		</dependency>
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>${jedis.version}</version>
		</dependency>
			<!-- 单元测试 -->
			<dependency>
				<groupId>junit</groupId>
				<artifactId>junit</artifactId>
				<version>${junit.version}</version>
			</dependency>
			<!-- 日志处理 -->
			<dependency>
				<groupId>org.slf4j</groupId>
				<artifactId>slf4j-log4j12</artifactId>
				<version>${slf4j.version}</version>
			</dependency>
			<!-- Mybatis -->
			<dependency>
				<groupId>org.mybatis</groupId>
				<artifactId>mybatis</artifactId>
				<version>${mybatis.version}</version>
			</dependency>
			<dependency>
				<groupId>org.mybatis</groupId>
				<artifactId>mybatis-spring</artifactId>
				<version>${mybatis.spring.version}</version>
			</dependency>
			<!-- MySql -->
			<dependency>
				<groupId>mysql</groupId>
				<artifactId>mysql-connector-java</artifactId>
				<version>${mysql.version}</version>
			</dependency>
			<!-- 连接池 -->
			<dependency>
				<groupId>com.alibaba</groupId>
				<artifactId>druid</artifactId>
				<version>${druid.version}</version>
			</dependency>
			<!-- Spring -->
			<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-context</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-webmvc</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-aspects</artifactId>
				<version>${spring.version}</version>
			</dependency>
			<!-- JSP相关 -->
			<dependency>
				<groupId>jstl</groupId>
				<artifactId>jstl</artifactId>
				<version>${jstl.version}</version>
			</dependency>
			<dependency>
				<groupId>javax.servlet</groupId>
				<artifactId>servlet-api</artifactId>
				<version>${servlet-api.version}</version>
				<scope>provided</scope>
			</dependency>
			<dependency>
				<groupId>javax.servlet</groupId>
				<artifactId>jsp-api</artifactId>
				<version>${jsp-api.version}</version>
				<scope>provided</scope>
			</dependency>
			<!-- 文件上传组件 -->
			<dependency>
				<groupId>commons-fileupload</groupId>
				<artifactId>commons-fileupload</artifactId>
				<version>${commons-fileupload.version}</version>
			</dependency>
			
			<dependency>
				<groupId>commons-net</groupId>
				<artifactId>commons-net</artifactId>
				<version>${commons-net.version}</version>
			</dependency>
			
			<!-- Jackson Json处理工具包 -->
			<dependency>
				<groupId>com.fasterxml.jackson.core</groupId>
				<artifactId>jackson-databind</artifactId>
				<version>${jackson.version}</version>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<resources>
			<resource>
				<directory>src/main/java</directory>
				<includes>
					<include>**/*.xml</include>
				</includes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<includes>
					<include>**/*.xml</include>
					<include>**/*.properties</include>
				</includes>
			</resource>
		</resources>
		<!-- tomcat插件,由于子项目不一定每个都是web项目,所以该插件只是声明,并未开启 -->
		<pluginManagement>
			<plugins>
				<!-- 配置Tomcat插件 -->
				<plugin>
					<groupId>org.apache.tomcat.maven</groupId>
					<artifactId>tomcat7-maven-plugin</artifactId>
					<version>${tomcat.version}</version>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>

JsonDemo1/pom.xml

代码语言:javascript复制
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>com.bjsxt</groupId>
		<artifactId>parent</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>jsonDemo1</artifactId>
	<packaging>war</packaging>
	<dependencies>
		<!-- JSP相关 -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<!-- 配置Tomcat插件 -->
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<configuration>
					<path>/</path>
					<port>8080</port>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

jsonDemo2/pom.xml

代码语言:javascript复制
<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.bjsxt</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>jsonDemo2</artifactId>
  <packaging>war</packaging>
  <dependencies>
  	<dependency>
				<groupId>org.springframework</groupId>
				<artifactId>spring-webmvc</artifactId>
			</dependency>
			<!-- JSP相关 -->
			<dependency>
				<groupId>jstl</groupId>
				<artifactId>jstl</artifactId>
			</dependency>
			<dependency>
				<groupId>javax.servlet</groupId>
				<artifactId>servlet-api</artifactId>
				<scope>provided</scope>
			</dependency>
			<dependency>
				<groupId>javax.servlet</groupId>
				<artifactId>jsp-api</artifactId>
				<scope>provided</scope>
			</dependency>
			<!-- Jackson Json处理工具包 -->
			<dependency>
				<groupId>com.fasterxml.jackson.core</groupId>
				<artifactId>jackson-databind</artifactId>
			</dependency>
  </dependencies>
  <build>
  	<plugins>
				<!-- 配置Tomcat插件 -->
				<plugin>
					<groupId>org.apache.tomcat.maven</groupId>
					<artifactId>tomcat7-maven-plugin</artifactId>
					<configuration>
						<path>/</path>
						<port>9090</port>
					</configuration>
				</plugin>
			</plugins>
  </build>
</project>

JsonP实现手动跨域

手动实现跨域的要求 1. ajax的请求方式必须是get 2. ajax的dataType必须是jsonp 3. 必须要有jsop的属性,后面的字符串可以其任意字符 4 在后端控制器方法中需要将这个字符串注入进来 5 将查询到的数据通过jsonUtil转换成json类型(需要jackson的jar包) 6 将jsonp属性字符串与json类型字符串进行手动拼接 return jsonp属性字符串 "(" json类型字符串 ")";

jsonDemo1的jsp页面(发送跨域请求)

代码语言:javascript复制
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="/js/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function(){
	$("#but").click(function(){
		$.ajax({
			type:"get",
			url:"http://localhost:9090/user/findUser",
			dataType:"jsonp",
			jsonp:"callback",
			success:function(data){
				alert(data);
				var str = "";
				for(i=0;i<data.length;i  ){
					str = data[i].userid " " data[i].username " " data[i].userage " ";
				}
				$("#show").html(str);
			}
		});
	});
});
</script>
</head>
<body>
	<span id="show"></span>
	<input type="button" value="OK" id="but"/>
</body>
</html>

jsonDemo2的controller

代码语言:javascript复制
@Controller
@RequestMapping("/user")
public class UserController {

	@RequestMapping("/findUser")
	@ResponseBody
	public Object findUser(String callback){
		Users user = new Users(1, "admin", 20);
		Users user1 = new Users(2, "zhangsan", 22);
		Users user2 = new Users(3, "lisi", 24);
		List<Users> list = new ArrayList<>();
		list.add(user);
		list.add(user1);
		list.add(user2);
		//json转换
		//MappingJacksonValue mv = new MappingJacksonValue(list);
		//mv.setJsonpFunction(callback);
		//return mv;
		String json=JsonUtils.objectToJson(list);
		return callback "(" json  ")";
	}
}

JsonUtils工具类(需要添加相关坐标jackson-databind)

代码语言:javascript复制
import java.util.List;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * JSON转换工具类
 */
public class JsonUtils {

    // 定义jackson对象
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将对象转换成json字符串。
     * <p>Title: pojoToJson</p>
     * <p>Description: </p>
     * @param data
     * @return
     */
    public static String objectToJson(Object data) {
    	try {
			String string = MAPPER.writeValueAsString(data);
			return string;
		} catch (JsonProcessingException e) {
			e.printStackTrace();
		}
    	return null;
    }
    
    /**
     * 将json结果集转化为对象
     * 
     * @param jsonData json数据
     * @param clazz 对象中的object类型
     * @return
     */
    public static <T> T jsonToPojo(String jsonData, Class<T> beanType) {
        try {
            T t = MAPPER.readValue(jsonData, beanType);
            return t;
        } catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
    
    /**
     * 将json数据转换成pojo对象list
     * <p>Title: jsonToList</p>
     * <p>Description: </p>
     * @param jsonData
     * @param beanType
     * @return
     */
    public static <T>List<T> jsonToList(String jsonData, Class<T> beanType) {
    	JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
    	try {
    		List<T> list = MAPPER.readValue(jsonData, javaType);
    		return list;
		} catch (Exception e) {
			e.printStackTrace();
		}
    	return null;
    }
} 

实现自动跨域(SpringMVC对JsonP的支持)

jsonDemo1的jsp页面同上

jsonDemo2的controller

代码语言:javascript复制
@Controller
@RequestMapping("/user")
public class UserController {

	@RequestMapping("/findUser")
	@ResponseBody
	public Object findUser(String callback){
		Users user = new Users(1, "admin", 20);
		Users user1 = new Users(2, "zhangsan", 22);
		Users user2 = new Users(3, "lisi", 24);
		List<Users> list = new ArrayList<>();
		list.add(user);
		list.add(user1);
		list.add(user2);
		//json转换
		MappingJacksonValue mv = new MappingJacksonValue(list);
		mv.setJsonpFunction(callback);
		return mv;
	}
}

测试结果

0 人点赞