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

时间:2022-07-22
本文章向大家介绍JsonP------实现跨域请求,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

JsonP技术

介绍

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

<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

<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

<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页面(发送跨域请求)

<%@ 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

@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)

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

@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;
	}
}

测试结果