# 传统web开发 SOP既可以作为网关服务开发,又可以作为传统的webapp服务开发,传统web开发意思是像普通的web开发那样提供restful接口,没有签名校验功能。 本篇介绍如何使用SOP进行传统web服务开发,即对接前端应用(H5、小程序、App)。 - 网关ZuulConfig继承WebappZuulConfiguration类 ```java @Configuration public class ZuulConfig extends WebappZuulConfiguration { static { new ManagerInitializer(); } } ``` 设置完毕,网关不在进行签名验证,网关统一的返回结果如下: ```json { "result": { ... } } ``` - 微服务OpenServiceConfig继承WebappServiceConfiguration类 ```java public class OpenServiceConfig extends WebappServiceConfiguration { ... } ``` 其它内容不变 - 前端app请求网关 请求格式为:`http://ip:port/rest/your_path`,其中`http://ip:port/rest/`为固定部分,后面跟微服务请求路径。 注意:为了确保各个微服务路径不冲突,必须保证类上方定义的`@RequestMapping`内容唯一,不与其它微服务重复。 下面是一个微服务的接口例子 ```java @RestController @RequestMapping("food") public class TraditionalWebappController { @ApiMapping(value = "getFoodById", method = RequestMethod.GET) public Food getFoodById(Integer id) { Food food = new Food(); food.setId(id); food.setName("香蕉"); food.setPrice(new BigDecimal(20.00)); return food; } // 加版本号 @ApiMapping(value = "getFoodById", method = RequestMethod.GET, version = "1.1") public Food getFoodById2(Integer id) { Food food = new Food(); food.setId(id); food.setName("香蕉2"); food.setPrice(new BigDecimal(22.00)); return food; } } ``` 这是一个`食品服务`例子,假设网关ip为10.0.1.11,端口8081;食品服务ip为10.0.1.22,端口2222 1. 网关访问:`http://10.0.1.11:8081/rest/food/getFoodById?id=2`。加版本号:`http://localhost:8081/rest/food/getFoodById?id=2&version=1.1` 2. 本地访问:`http://10.0.1.22:2222/food/getFoodById/?id=2` 更多例子,可查看源码类:`TraditionalWebappController.java` 由此可见,对于前端调用者来说,它把网关看做一个大服务,只访问网关提供的请求,不需要关心网关后面的路由转发。网关后面各个微服务独自管理, 微服务之间的调用可以使用dubbo或feign,有了版本号的管理,可以做到服务的平滑升级,对用户来说都是无感知的。结合SOP-Admin提供的上下线功能, 可实现预发布环境功能。 - 封装请求工具【可选】 封装请求,方便调用,针对vue的封装如下: ```js import axios from 'axios' // 创建axios实例 const client = axios.create({ baseURL: process.env.BASE_API, // api 的 base_url timeout: 5000, // 请求超时时间 headers: { 'Content-Type': 'application/json' } }) const RequestUtil = { /** * 请求接口 * @param url 请求路径,如http://localhost:8081/rest/food/getFoodById * @param data 请求数据,json格式 * @param callback 成功回调 * @param errorCallback 失败回调 */ post: function(url, data, callback, errorCallback) { client.post(url, data) .then(function(response) { const resp = response.result const code = resp.code // 成功,网关正常且业务正常 if (code === '10000' && !resp.sub_code) { callback(resp) } else { // 报错 Message({ message: resp.msg, type: 'error', duration: 5 * 1000 }) } }) .catch(function(error) { console.log('err' + error) // for debug errorCallback && errorCallback(error) }) } } export default RequestUtil ``` jQuery版本如下: ```js var RequestUtil = { /** * 请求接口 * @param url 请求路径,如http://localhost:8081/rest/food/getFoodById * @param data 请求数据,json格式 * @param callback 成功回调 * @param errorCallback 失败回调 */ post: function(url, data, callback, errorCallback) { $.ajax({ url: 'http://localhost:8081/api' // 网关url , type: 'post' , headers: { 'Content-Type': 'application/json' } , data: data ,success:function(response) { var resp = response.result var code = resp.code // 成功,网关正常且业务正常 if (code === '10000' && !resp.sub_code) { callback(resp) } else { // 报错 alert(resp.msg); } } , error: function(error) { errorCallback && errorCallback(error) } }); } } ``` jQuery调用示例: ```js $(function () { var data = { id: 1 ,name: '葫芦娃' } RequestUtil.post('http://localhost:8081/rest/food/getFoodById', data, function (result) { console.log(result) }); }) ```