前言
对于刚入行时的小白误以为前后端分离就是,前端代码不使用java了。但是其实并不是这样的,前后端分离就是前段写前端的代码,后端完成后端的代码互不干扰。前端编写的时候,只要后端给提供相应的接口过去就可以了
1、跨域问题
URL | 说明 | 是否允许通信 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一域名下 | 允许 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.js http://www.a.com/b.js | 同一域名,不同端口 | 不允许 |
http://www.a.com/a.js https://www.a.com/b.js | 同一域名,不同协议 | 不允许 |
http://www.a.com/a.js http://70.32.92.74/b.js | 域名和域名对应ip | 不允许 |
http://www.a.com/a.js http://script.a.com/b.js | 主域相同,子域不同 | 不允许 |
http://www.a.com/a.js http://a.com/b.js | 同一域名,不同二级域名(同上) | 不允许(cookie这种情况下也不允许访问) |
http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允许 |
1.1、前后端代码不在一个服务器上,域名也不一样,很明显就是要跨域
1.1.1、小白:什么是跨域
正常情况下,我们拿浏览器去访问的时候,直接访问后后端服务器,这样是不跨域,而跨域就是我们浏览器访问前端代码,通过前端代码访问后端服务器。这样就是跨域了。前端代码相当于是一个中介
1.1.2、配置拦截器
@Component
@Slf4j
public class CORSInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//添加跨域CORS
// 服务器不在一起,下面这个跨域是马川 给我的,好用
String originHeader = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", originHeader);
response.addHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,accessToken");
response.addHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
return true;
}
}
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter{
@Autowired //解决跨域
private CORSInterceptor corsInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(corsInterceptor);
super.addInterceptors(registry);
}
}
1.1.3、将前端首页缓存下来(这样一来,每次我们登录之后不管方位的哪个页面都是首页)
(可以是redis,也可以是ehcache,也可以是数据库)
1、配置文件中首页的url,因为下面下面是使用的阿里云的服务器,所以用了下面的方法,大家也可以直接通过url进行缓冲首页面
2、这样的话就是相当于是走了前端代理了,使用的后端的url,打开之后访问的是前端。所以这里要求我们严格编写服务器url路径(设置一个url统一的前缀,比如我这里是duodian)
# 前后端分离
duodianyouhui.page.prefix=duodian-youhui-admin/index.html
package com.duodian.youhui.admin.moudle;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import com.duodian.youhui.admin.Exceptions.AppException;
import com.duodian.youhui.admin.bean.ResponseBean;
import com.duodian.youhui.admin.config.CasConfig;
import com.duodian.youhui.admin.config.cache.EhCacheObjectDataUtil;
import com.duodian.youhui.admin.constants.CacheConstants;
import com.duodian.youhui.admin.utils.OSSPageUtil;
import com.duodian.youhui.admin.utils.SdkHttpHelper;
import com.duodian.youhui.data.http.HttpBackBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author chuan.ma
* @since 2018/3/13
*/
@Controller
@Slf4j
public class IndexController {
@Resource
private EhCacheObjectDataUtil ehCacheObjectDataUtil;
//前后端分离的首页
@Value("${duodianyouhui.page.prefix}")
private String asouPage;
@RequestMapping("/**")
public void index(HttpServletResponse response, HttpServletRequest request) throws Exception {
String content = getPageCache();
try {
if (StringUtils.isEmpty(content)) {
// 将页面下载下来,也可以比使用oss下载,这里用的是oss,这里只传递了一个 首页面。所以以后都是登陆后进入首页面
content = IOUtils.toString(OSSPageUtil.download(asouPage), "UTF-8");
// HttpBackBean httpBackBean = SdkHttpHelper.handleGet("http://testquan.dangqugame.cn/duodian-youhui-admin/index.html", null, null, SdkHttpHelper.OVERTIME);
setPageCache(content);
}
} catch (Exception e) {
log.error(e.getMessage());
}
if(request.getRequestURI().contains("swagger")){
}
response.setContentType("text/html;charset=utf-8"); //相当于是将流变成的浏览器端能识别的html,也就是相当于浏览器登陆
response.getWriter().write(content);
}
private String getPageCache() {
return (String) ehCacheObjectDataUtil.getData(CacheConstants.CACHE_PUBLIC_PERSON,CacheConstants.KEY_PUBLIC_PERSON);
}
private void setPageCache(String content) {
log.info(content);
ehCacheObjectDataUtil.setData(CacheConstants.CACHE_PUBLIC_PERSON, CacheConstants.KEY_PUBLIC_PERSON,content);
}
/**
* 刷新页面
*/
@RequestMapping("/h5/refurbish")
@ResponseBody
public boolean refurbishCache() {
return ehCacheObjectDataUtil.delete(CacheConstants.CACHE_PUBLIC_PERSON, CacheConstants.KEY_PUBLIC_PERSON);
}
}
1.1.4、如果是使用的单点登录,登录之后可能不会直接访问到域名,而是后缀加的jsessionid,所以要去掉,springBoot启动main中添加如下
public class AdminApplication extends SpringBootServletInitializer implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class, args);
}
//继承SpringBootServletInitializer 解决单点登录之后,请求头中出现 的jsesssionid 不能正常跳转到前端域名的问题
//之前使用的sendRedirect()不管用,也不知道为啥,反正使用下面这种就没错了
public void onStartup(ServletContext servletContext) throws ServletException {
super.onStartup(servletContext);
// This will set to use COOKIE only
servletContext.setSessionTrackingModes(
Collections.singleton(SessionTrackingMode.COOKIE)
);
// This will prevent any JS on the page from accessing the
// cookie - it will only be used/accessed by the HTTP transport
// mechanism in use
SessionCookieConfig sessionCookieConfig =
servletContext.getSessionCookieConfig();
sessionCookieConfig.setHttpOnly(true);
}
}
2、同一个服务器的前后端分离
2.1、同一个服务器但是子域名不相同,也是跨域。但是这样的就不需要设置上面的IndexController,将前端页面解析下来了。
后端登录后还是去掉jssessionid。这样的话访问的就是简单的域名了,比如,server.healerjean.com,这个时候,我们给它跳转到前端的url去
#服务器登录之后跳转到前端url
server.login.redirect.url=quan.dangqugame.cn
@Value("${server.login.redirect.url}")
private String server_login_redirect_url;
/**
* 首页面进入之后,跳转到前端url界面,如果是前后端分离用的两个域名的情况下
* @return
*/
@GetMapping(value = {"/",""} )
public String loginDev(){
return "redirect://"+server_login_redirect_url;
}