---
title: 请求跨域问题
date: 2017-06-01 19:33:33
update: 2017-06-01 19:33:33
categories: JAVA
tags: [ajax]
---
### 1 解决跨域问题
#### 1.1 问题产生原因
浏览器对ajax请求的限制,不允许跨域请求资源。
http://www.a.com -> http://www.b.com 是跨域
http://www.a.com -> http://www.a.com:8080 是跨域
http://a.a.com ->http://b.a.com 是跨域
http://www.a.com -> http://www.a.com/api 不是
总结:
不同的域名或不同的端口都是跨域请求。

#### 1.2 测试
json.jsp资源
```javascript
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
/* String callback = request.getParameter("callback");
if (null != callback) {
out.print(callback + "({\"abc\":123})");
} else {
out.print("{\"abc\":123})");
} */
out.print("{\"abc\": \"123\""});
/*out.print("fun({"\"abc\": \"123\""})");*/
%>
```
test-json.htm文件,与json.jsp资源属于不同的项目中
```javascript
Insert title here
```
经过测试可以得出,script标签是可以跨域请求的,而ajax不能跨域请求
```
```
如果换成script标签请求资源
```
```
会出现以下错误,意思是js解析出错了,因为资源返回的是{"abc":"123"}json格式的字符串数据无法解析成js

如果资源返回结果变成out.print("fun({"\"abc\": \"123\""})");
就会出现fun is not defined错误,说明可以解析js,但是返回的这个fun函数找不到。那么就在test-json.htm中定义一个fun函数
```javascript
function fun(data){
alert(data.abc);
}
```
再次请求弹出返回的数据。
以上就是jsonp的原理:
```
Jsonp的原理:
1、 jsonp通过script标签的src可以跨域请求的特性,加载资源
2、 将加载的资源(通过一个方法名将数据进行包裹)当做是js脚本解析
3、 定义一个回调函数,获取传入的数据
```
### 2 使用jsonp,处理跨域请求
请求代码
```javascript
$.ajax({
url: "http://manage.taotao.com/rest/api/item/cat?callback=category.getDataService",
dataType: "jsonp",
success: function(data) {
// data的值:category.getDataService({abc: 123})
alert(data.abc);
}
});
```
或者
```javascript
$.getJSONP("http://manage.taotao.com/rest/api/item/cat?callback=category.getDataService", category.getDataService)
var category = {
getDataService : function(a){};
}
```
后台接口代码
```java
@RequestMapping("api/item/cat")
@Controller
public class ApiItemCatController {
@Autowired
private ItemCatService itemCatService;
// private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* @Title queryItemCat
* @Description 对外提供查询类目借口数据
* @return ResponseEntity
* @throws
* url:http://manage.taotao.com/rest/api/item/cat?callback=category.getDataService
*/
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity queryItemCat(@RequestParam("callback") String callback) {
try {
ItemCatResult itemCatResult = this.itemCatService.queryAllToTree();
String json = MAPPER.writeValueAsString(itemCatResult);
if (callback.isEmpty()) {
return ResponseEntity.ok(json);
}
return ResponseEntity.ok(callback + "(" + json + ");"); // 拼接成js
} catch (Exception e) {
e.printStackTrace();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
```
### 3 统一解决jsonp请求,并处理中文乱码
#### 3.1 接口
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.taotao.common.bean.ItemCatResult;
import com.taotao.manage.service.ItemCatService;
/**
* @ClassName ApiItemCatController
* @Description
* @Author youtanzhi
* @Date 2017年2月14日 下午9:29:43
* url: http://manage.taotao.com/rest/api/item/cat
*/
@RequestMapping("api/item/cat")
@Controller
public class ApiItemCatController {
@Autowired
private ItemCatService itemCatService;
// private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* @Title queryItemCat
* @Description 对外提供查询类目借口数据
* @return ResponseEntity
* @throws
*/
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity queryItemCat(@RequestParam("callback") String callback) {
try {
ItemCatResult itemCatResult = this.itemCatService.queryAllToTree();
return ResponseEntity.ok(itemCatResult);
} catch (Exception e) {
e.printStackTrace();
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
```
#### 3.2 初始化servlet.xml文件中配置消息转化器
```xml
```
#### 3.3 自定义消息转化器处理类
引用jar
```
org.springframework
spring-web
${spring.version}
org.apache.commons
commons-lang3
org.apache.commons
commons-io
javax.servlet
servlet-api
provided
```
处理类
```java
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonProcessingException;
public class CallbackMappingJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
// 做jsonp的支持的标识,在请求参数中加该参数
private String callbackName;
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
// 从threadLocal中获取当前的Request对象
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
String callbackParam = request.getParameter(callbackName);
if (StringUtils.isEmpty(callbackParam)) {
// 没有找到callback参数,直接返回json数据
super.writeInternal(object, outputMessage);
} else {
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
try {
String result = callbackParam + "(" + super.getObjectMapper().writeValueAsString(object) + ");";
IOUtils.write(result, outputMessage.getBody(), encoding.getJavaName());
} catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
}
}
}
public String getCallbackName() {
return callbackName;
}
public void setCallbackName(String callbackName) {
this.callbackName = callbackName;
}
}
```
请求跨域问题