之前了解了跨域,只是有些印象,正好这次前后端分离可以用到,在此详细记录一下。
1.跨域问题:浏览器出于安全考虑,不允许js的ajax跨域请求资源。
跨域的定义:域名或端口号不同都是跨域
2.解决跨域问题:本文的解决方案:jsonp
3.jsonp原理:
jsonp即json+padding,动态创建script标签,利用script标签的src属性可以获取任何域下的js脚本,通过这个特性(也可以说是漏洞),服务器端不再返回json格式,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域。
4.jsonp解决方案实现
写一个通用的类实现jsonp通用支持,让每一个request的请求都经过该类,若为跨域请求则使用jsonp进行处理,否则就正常处理。该类继承MappingJackson2HttpMessageConverter然后进行扩展。
package com.bdit.common;
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);
System.out.println(callbackParam);
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)+");";
System.out.println(result);
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;
}
}
5.前端调用格式:
前端调用在需要跨域请求的原url上添加?callback=任意函数名,同时需要在ajax的请求中设置数据乐西dataType:"jsonp"。
示例:
关于jsonp优缺点情况这篇文章《jsonp的原理,应用场景,优缺点》
关于跨域的解决方案请看此篇《前后端分离跨域问题解决方案》