服务端交互最佳实践
JUI使用前后端分离的架构模式,通过 API 的形式和任何技术栈的服务端应用一起工作。
api
├── axios.js #HTTP配置
├── index.js #API请求
└── request.js #请求方法
HTTP配置
JUI对axios做了基本的封装,配置了请求和响应拦截器。可以在axios.js
文件中扩展更多axios的配置。
/**
* axios 基础配置
*/
import axios from 'axios'
// import auth from "@/utils/auth"
axios.defaults.timeout = 5000
axios.defaults.baseURL = 'http://localhost:3000'
axios.defaults.withCredentials = true //发起请求携带cookie(CROS跨域需要服务端的支持)
// 将token传回服务器认证登录状态
// axios.defaults.headers.common['Authorization'] = auth.getToken()
//请求拦截
axios.interceptors.request.use((config) => {
return config
}, (err) => {
return Promise.reject(err)
})
//响应拦截//
axios.interceptors.response.use((res) => {
return res
}, (err) => {
//错误处理
// 可处理用户登录基础信息,比如用户名,token,过期时间等
// if (error.response.status === 403) {
// // 403
// }
// if (error.response.status === 500) {
// // 500
// }
// if (error.response.status === 502) {
// // 502
// }
// if (error.response.status === 404) {
// // 404
// }
return Promise.reject(err)
})
export default axios
请求方法
JUI对HTTP请求做了GET
和POST
基本封装,可以在request.js
文件中扩展更多方法。
/**
* 统一管理和封装HTTP请求
*/
import axios from './axios'
import qs from 'qs'
export default async (url, params = {}, method = 'POST', isUpload = false) => {
method = method.toUpperCase()
if (method === 'GET') {
const res = await axios.get(url, {
params
})
return res.data
} else if (method === 'POST') {
const normal = {
transformRequest: [
function (data) {
return qs.stringify(data)
}
]
}
const upload = {
headers: {
'Content-Type': 'multipart/form-data'
}
}
const res = await axios.post(url, params, isUpload ? upload : normal)
return res.data
}
// 请自行添加其它方法
}
集中管理API
JUI使用集中管理请求接口的方式,便于维护和调用。
/**
* 集中管理请求接口
*/
import fetch from './request'
// 接口demo
export const apiDemo = params => fetch('/api/demo', params, 'POST')
调用API
import React, { PureComponent, Fragment } from 'react'
import { apiDemo } from '@/api' //调用接口
export default class User extends PureComponent {
state = {
apiData: {},
}
initData = async () => { //异步方式处理请求
const res = await apiDemo({})
this.setState({
apiData: res.data
})
}
componentDidMount() {
this.initData()
}
render() {
const { apiData } = this.state
console.log(apiData) //获取API请求数据
return (
<Fragment>
...
</Fragment>
)
}
}
Service层
在前后端分离的情况下,前后端常常是各成体系与团队,那么前后端的沟通也就成了项目开发中的主要矛盾之一。后端提供的数据格式常常并不符合前端界面渲染所需要的数据格式,并且考虑到业务需求的经常变更,后台接口也可能会发生频繁变动。此时就需要前端能够建立专门的接口服务层(service层)对上屏蔽这种变化,并且将数据处理与渲染逻辑分离,保证界面层的稳定性、及逻辑功能模块扩展性和可维护性。
建立Service.js文件处理数据
// service.js
export default async (data) => {
// 处理 data
return {...data}
}
使用Service
import React, { PureComponent, Fragment } from 'react'
import { apiDemo } from '@/api' //调用接口
import Service from './service' //引入Service服务层
export default class User extends PureComponent {
state = {
apiData: {},
}
initData = async () => { //异步方式处理请求
const apiDatas = await apiDemo({})
const res = await Service(apiDatas) //处理或封装接口数据
this.setState({
apiData: res.data
})
}
componentDidMount() {
this.initData()
}
render() {
const { apiData } = this.state
console.log(apiData) //获取经过service层处理后的数据
return (
<Fragment>
...
</Fragment>
)
}
}
跨域访问
JUI使用前后端分离的架构模式,前端可以单独部署发布,当访问后端服务接口就会出现跨域。建议使用跨域资源共享(CORS)
实现跨域。所有现代浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
普通跨域请求只需服务端设置Access-Control-Allow-Origin
即可,前端无须设置,若要携带cookie请求,前后端都需要设置。若后端设置成功,前端浏览器控制台则不会出现跨域报错信息,反之,说明没设成功。
前端设置
由于JUI使用了axios
,只需在api/axios.js
文件中配置:
axios.defaults.withCredentials = true //发起请求携带cookie(CROS跨域需要服务端的支持)
服务端设置
- Java后台
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
- Nodejs后台
// 允许所有的请求形式 (跨域)
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", req.headers.origin) //需要显示设置来源
res.header("Access-Control-Allow-Credentials", true) //带cookies
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept")
next()
})
需注意的是:由于同源策略的限制,所读取的cookie为跨域请求接口所在域的cookie,而非当前页。