传统web开发

默认情况下SOP只提供开放接口,也可以同时提供restful接口,即程序提供一部分的开放接口,同时提供一部分restful接口。

默认情况下提供restful功能是关闭的,开启方式如下:

  • 打开sop-gateway配置文件,新增一行配置:
  1. # 提供restful接口
  2. sop.restful.enable=true
  • 前端app请求网关(2.4.1之后有变动)

请求格式:

2.4.1版本之前: http://ip:port/rest/your_path,其中http://ip:port/rest/为固定部分,后面跟微服务请求路径。

2.4.1之后: http://ip:port/rest/服务id/your_path,其中http://ip:port/rest/为固定部分,后面跟微服务请求路径。

注意,2.4.1开始多了一个服务id作为区分,这样做是为了避免各微服务之间url冲突,假如两个微服务都有一个叫/getItems这样的接口那么调用http://ip:port/rest/getItems接口网关无法做出正确的路由,虽然可以在代码上进行规范,为了防止万一,还是强行加上了,避免采坑。可以指定sop.restful.old-model=true强制使用老的调用方式

可在微服务端指定一个配置:sop.restful.prefix=xxx。请求路径将变成:http://ip:port/rest/xxx/your_path

下面是一个微服务的接口例子

  1. @RestController
  2. @RequestMapping("food")
  3. public class TraditionalWebappController {
  4. @RequestMapping(value = "getFoodById", method = RequestMethod.GET)
  5. public Food getFoodById(Integer id) {
  6. Food food = new Food();
  7. food.setId(id);
  8. food.setName("香蕉");
  9. food.setPrice(new BigDecimal(20.00));
  10. return food;
  11. }
  12. }

这是一个食品服务例子,serviceId为food-service,假设网关ip为10.0.1.11,端口8081;食品服务ip为10.0.1.22,端口2222

  1. 网关访问:http://10.0.1.11:8081/rest/food-service/food/getFoodById?id=2

  2. 本地访问:http://10.0.1.22:2222/food/getFoodById/?id=2

更多例子,可查看源码类:TraditionalWebappController.java

由此可见,对于前端调用者来说,它把网关看做一个大服务,只访问网关提供的请求,不需要关心网关后面的路由转发。网关后面各个微服务独自管理,微服务之间的调用可以使用dubbo或feign,有了版本号的管理,可以做到服务的平滑升级,对用户来说都是无感知的。结合SOP-Admin提供的上下线功能,可实现预发布环境功能。

  • 封装请求工具【可选】

封装请求,方便调用,针对vue的封装如下:

  1. import axios from 'axios'
  2. // 创建axios实例
  3. const client = axios.create({
  4. baseURL: process.env.BASE_API, // api 的 base_url
  5. timeout: 5000, // 请求超时时间
  6. headers: { 'Content-Type': 'application/json' }
  7. })
  8. const RequestUtil = {
  9. /**
  10. * 请求接口
  11. * @param url 请求路径,如http://localhost:8081/rest/food-service/food/getFoodById
  12. * @param data 请求数据,json格式
  13. * @param callback 成功回调
  14. * @param errorCallback 失败回调
  15. */
  16. post: function(url, data, callback, errorCallback) {
  17. client.post(url, data)
  18. .then(function(response) {
  19. const resp = response.result
  20. const code = resp.code
  21. // 成功,网关正常且业务正常
  22. if (code === '10000' && !resp.sub_code) {
  23. callback(resp)
  24. } else {
  25. // 报错
  26. Message({
  27. message: resp.msg,
  28. type: 'error',
  29. duration: 5 * 1000
  30. })
  31. }
  32. })
  33. .catch(function(error) {
  34. console.log('err' + error) // for debug
  35. errorCallback && errorCallback(error)
  36. })
  37. }
  38. }
  39. export default RequestUtil

jQuery版本如下:

  1. var RequestUtil = {
  2. /**
  3. * 请求接口
  4. * @param url 请求路径,如http://localhost:8081/rest/food-service/food/getFoodById
  5. * @param data 请求数据,json格式
  6. * @param callback 成功回调
  7. * @param errorCallback 失败回调
  8. */
  9. post: function(url, data, callback, errorCallback) {
  10. $.ajax({
  11. url: 'http://localhost:8081' // 网关url
  12. , type: 'post'
  13. , headers: { 'Content-Type': 'application/json' }
  14. , data: data
  15. ,success:function(response) {
  16. var resp = response.result
  17. var code = resp.code
  18. // 成功,网关正常且业务正常
  19. if (code === '10000' && !resp.sub_code) {
  20. callback(resp)
  21. } else {
  22. // 报错
  23. alert(resp.msg);
  24. }
  25. }
  26. , error: function(error) {
  27. errorCallback && errorCallback(error)
  28. }
  29. });
  30. }
  31. }

jQuery调用示例:

  1. $(function () {
  2. var data = {
  3. id: 1
  4. ,name: '葫芦娃'
  5. }
  6. RequestUtil.post('http://localhost:8081/rest/food-service/food/getFoodById', data, function (result) {
  7. console.log(result)
  8. });
  9. })