前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go(六)来来来,教你怎么远程调用

Go(六)来来来,教你怎么远程调用

作者头像
lomtom
发布2021-12-24 13:24:38
6950
发布2021-12-24 13:24:38
举报
文章被收录于专栏:博思奥园

每个微服务应用难免会有远程调用,那么在JAVA里面,有很多种远程调用的方法,最基础的手写HTTP调用,或者使用restTetmplate,再到使用openfeign仅仅写个接口就可以实现调用。

那么在Go语言里,Go也提供了Http调用的包net/http,或者使用http组件(gentleman、grequests、heimdall等)或者使用更高级的RPC调用,也有rpc框架(GRPC)。

那么在本章节探讨如何在Go语言里实现HTTP调用。

接口定义

首先进行接口的定义,方便后续进行远程调用。

这里以JAVA为例,以最常见的User实体,来编写相对应的操作。

例如:

代码语言:javascript
复制
GET 查询列表
GET 查询单个用户
POST 保存用户
PUT 修改单个用户
DELETE 删除单个用户

实体类

代码语言:javascript
复制
@Data
@ApiModel("用户实体")
@NoArgsConstructor
public class User {
    @ApiModelProperty(notes = "用户编号", example = "000001")
    private Long id;

    @NotEmpty(message = "用户名不能为空")
    @ApiModelProperty(notes = "用户名", example = "小欧")
    private String username;

    @NotEmpty(message = "密码不能为空")
    @ApiModelProperty(notes = "密码", example = "123456")
    private String password;

    @NotEmpty(message = "手机号不能为空")
    @ApiModelProperty(notes = "手机号", example = "110")
    private String telNew;

    @TableLogic
    @ApiModelProperty(notes = "是否删除", example = "true")
    private Boolean deleted;

    public User(Long id, String username, String password, String telNew, Boolean deleted) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.telNew = telNew;
        this.deleted = deleted;
    }
}

接口

其次,编写相应接口

代码语言:javascript
复制
@Api(tags = "用户管理")
@RestController
@RequestMapping("user")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class UserController {

    private final UserService userService;

    private final IdGen idGen;

    @ApiOperation("查看用户列表")
    @GetMapping
    public Result list(@RequestParam(required = false) Integer page,@RequestParam(required = false) Integer pageSize) {
        Page<User> userPage = new Page<>();
        userPage.setCurrent(page==null?1:page);
        userPage.setSize(pageSize==null?10:pageSize);
        Page<User> page1 = userService.page(userPage);
        return Result.ok("page", page1);
    }

    @ApiOperation("获取单个用户信息")
    @GetMapping("/{id}")
    public Result info(@PathVariable Long id) {
        User user = userService.getById(id);
        return Result.ok("user", user).put("id", id);
    }

    @ApiOperation("保存用户信息")
    @PostMapping
    public Result save(@RequestBody @Validated User user) {
        long id = idGen.nextId();
        user.setId(id);
        boolean save = userService.save(user);
        return Result.ok("save", save).put("id",id);
    }

    @ApiOperation("更新用户信息")
    @PutMapping
    public Result update(@RequestBody @Validated User user) {
        boolean update = userService.updateById(user);
        return Result.ok("update", update);
    }

    @ApiOperation("删除用户信息")
    @DeleteMapping("/{id}")
    public Result delete(
            @PathVariable
            @NotNull(message = "不能为空")
            Long id) {
        boolean remove = userService.removeById(id);
        return Result.ok("remove", remove).put("id",id);
    }
}

Http请求调用

基本的GET请求

代码语言:javascript
复制
// 基本的GET请求
func TestHttp(t *testing.T) {
 res, err := http.Get("http://localhost:8080/user")
 if err != nil {
  log.Fatalf("did not connect: %v", err)
  return
 }
 defer func(Body io.ReadCloser) {
  err := Body.Close()
  if err != nil {
   log.Fatalf("did not close: %v", err)
   return
  }
 }(res.Body)
 if res.StatusCode == 200 {
  log.Printf("success")
  name, err := ioutil.ReadAll(res.Body)
  if err != nil {
   log.Fatalf("could not greet: %v", err)
  }
  log.Printf("Greeting: %s", name)
 }
}

结果:

代码语言:javascript
复制
2021/09/07 18:17:38 Greeting: 
{
 "status":10020000,
 "resMsg":"请求成功",
 "data":{
  "page":{
  "records":[
   {
    "id":1,
    "username":"lomtom",
    "password":"123345",
    "telNew":"110",
    "deleted":false
   },{
    "id":2,
    "username":"小菜",
    "password":"123456",
    "telNew":"112",
    "deleted":false
    }],
  "total":2,
  "size":10,
  "current":1,
  "orders":[],
  "hitCount":false,
  "searchCount":true,
  "pages":1
  }
 }
}

GET请求 携带参数

若要在GET请求后携带参数,可以选择在URL后面进行拼接,当然也可以采用以下方式。

代码语言:javascript
复制
// GET请求 携带参数 (除了拼接)
func TestHttp1(t *testing.T) {
 params := url.Values{}
 Url, err := url.Parse("http://localhost:8080/user")
 if err != nil {
  return
 }
 params.Set("page", "2")
 params.Set("pageSize", "10")
 Url.RawQuery = params.Encode()
 urlPath := Url.String()
 res, err := http.Get(urlPath)
 if err != nil {
  log.Fatalf("did not connect: %v", err)
  return
 }
 defer func(Body io.ReadCloser) {
  err := Body.Close()
  if err != nil {
   log.Fatalf("did not close: %v", err)
   return
  }
 }(res.Body)
 if res.StatusCode == 200 {
  log.Printf("success")
  name, err := ioutil.ReadAll(res.Body)
  if err != nil {
   log.Fatalf("could not greet: %v", err)
  }
  log.Printf("Greeting: %s", name)
 }
}

结果:

代码语言:javascript
复制
2021/09/07 18:17:38 Greeting: 
{
  "status": 10020000,
  "resMsg": "请求成功",
  "data": {
    "page": {
      "records": [
        {
          "id": 1,
          "username": "lomtom",
          "password": "123345",
          "telNew": "110",
          "deleted": false
        },
        {
          "id": 2,
          "username": "小菜",
          "password": "123456",
          "telNew": "112",
          "deleted": false
        }
      ],
      "total": 2,
      "size": 10,
      "current": 1,
      "orders": [],
      "hitCount": false,
      "searchCount": true,
      "pages": 1
    }
  }
}

基本的POST请求(form)

注意:该方法对应的接口接受类型必须也为表单接收,那么在java的接口需要去掉save方法里的@RequestBody注解,否则将调用失败。

代码语言:javascript
复制
// 基本的POST请求 form
func TestHttp2(t *testing.T) {
 params := url.Values{}
 params.Set("username", "小小")
 params.Set("password", "123456")
 params.Set("telNew", "112")
 res, err := http.PostForm("http://localhost:8080/user", params)
 if err != nil {
  log.Fatalf("did not connect: %v", err)
  return
 }
 defer func(Body io.ReadCloser) {
  err := Body.Close()
  if err != nil {
   log.Fatalf("did not close: %v", err)
   return
  }
 }(res.Body)
 if res.StatusCode == 200 {
  log.Printf("success")
  name, err := ioutil.ReadAll(res.Body)
  if err != nil {
   log.Fatalf("could not greet: %v", err)
  }
  log.Printf("Greeting: %s", name)
 }
}

结果:

代码语言:javascript
复制
2021/09/07 18:22:12 Greeting: 
{
  "status": 10020000,
  "resMsg": "请求成功",
  "data": {
    "save": true,
    "id": 1435186634277519360
  }
}
2021-09-07 18:22:12.748 DEBUG 16028 --- [nio-8080-exec-2] c.l.d.mapper.UserMapper.insert           : ==>  Preparing: INSERT INTO user ( id, username, password, tel_new ) VALUES ( ?, ?, ?, ? )
2021-09-07 18:22:12.748 DEBUG 16028 --- [nio-8080-exec-2] c.l.d.mapper.UserMapper.insert           : ==> Parameters: 1435186634277519360(Long), 小小(String), 123456(String), 112(String)
2021-09-07 18:22:12.752 DEBUG 16028 --- [nio-8080-exec-2] c.l.d.mapper.UserMapper.insert           : <==    Updates: 1

POST请求(body)

该方法为将参数放在请求的body部分。

  1. 同样需要注意的是,在java的接口需要加上save方法里的@RequestBody注解,否则将调用失败。
  2. 请求参数不能是自定义的结构体,必须是map类型,否则接口将匹配失败,猜测与自定义结构体的转换有关。
  3. 需要设置请求头部参数resq.Header.Set("Content-Type", "application/json")
代码语言:javascript
复制
// POST请求 body
func TestHttp3(t *testing.T) {
 //params := struct {
 // username, password, telNew string
 //}{"小小", "123456", "112"}
 //str, err := json.Marshal(params)
 //使用结构体 接口匹配不上

 params := make(map[string]interface{})
 params["username"] = "小小"
 params["password"] = "123456"
 params["telNew"] = "112"
 str, err := json.Marshal(params)
 resq, err := http.NewRequest("POST","http://localhost:8080/user", bytes.NewBuffer(str))
 if err != nil {
  log.Fatalf("error: %v", err)
  return
 }
 resq.Header.Set("Content-Type", "application/json")
 res, err := http.DefaultClient.Do(resq)
 if err != nil {
  log.Fatalf("did not connect: %v", err)
  return
 }
 defer func(Body io.ReadCloser) {
  err := Body.Close()
  if err != nil {
   log.Fatalf("did not close: %v", err)
   return
  }
 }(res.Body)
 if res.StatusCode == 200 {
  log.Printf("success")
  name, err := ioutil.ReadAll(res.Body)
  if err != nil {
   log.Fatalf("could not greet: %v", err)
  }
  log.Printf("Greeting: %s", name)
 }
}

结果:

代码语言:javascript
复制
2021/09/08 16:05:30 Greeting: 
{
  "status": 10020000,
  "resMsg": "请求成功",
  "data": {
    "save": true,
    "id": 1435514618490388480
  }
}
2021-09-08 16:05:30.857 DEBUG 6100 --- [nio-8080-exec-6] c.l.d.mapper.UserMapper.insert           : ==>  Preparing: INSERT INTO user ( id, username, password, tel_new ) VALUES ( ?, ?, ?, ? )
2021-09-08 16:05:30.873 DEBUG 6100 --- [nio-8080-exec-6] c.l.d.mapper.UserMapper.insert           : ==> Parameters: 1435514618490388480(Long), 小小(String), 123456(String), 112(String)
2021-09-08 16:05:30.879 DEBUG 6100 --- [nio-8080-exec-6] c.l.d.mapper.UserMapper.insert           : <==    Updates: 1

PUT 请求

对于net/http,暂时提供了两种接口GetPost,那么对于PUTDELETE的实现,就需要使用它的高级功能了。

  1. 首先使用http.NewRequest申明一个新的请求,设置相对应的请求方式、url、参数等
  2. 再使用http.DefaultClient.Do(resq)发起请求即可
代码语言:javascript
复制
// PUT 请求
func TestHttp4(t *testing.T) {
 //params := struct {
 // id,username, password, telNew string
 //}{"1435514618490388480""小小", "123456", "112"}
 //str, err := json.Marshal(params)
 //使用结构体 接口匹配不上

 params := make(map[string]interface{})
 params["id"] = "1435514618490388480"
 params["username"] = "小道科"
 params["password"] = "123456"
 params["telNew"] = "112"
 str, err := json.Marshal(params)
 resq, err := http.NewRequest("PUT","http://localhost:8080/user", bytes.NewBuffer(str))
 if err != nil {
  log.Fatalf("error: %v", err)
  return
 }
 resq.Header.Set("Content-Type", "application/json")
 res, err := http.DefaultClient.Do(resq)
 if err != nil {
  log.Fatalf("did not connect: %v", err)
  return
 }
 defer func(Body io.ReadCloser) {
  err := Body.Close()
  if err != nil {
   log.Fatalf("did not close: %v", err)
   return
  }
 }(res.Body)
 if res.StatusCode == 200 {
  log.Printf("success")
  name, err := ioutil.ReadAll(res.Body)
  if err != nil {
   log.Fatalf("could not greet: %v", err)
  }
  log.Printf("Greeting: %s", name)
 }
}

结果:

代码语言:javascript
复制
2021/09/08 16:09:47 Greeting:
{
  "status": 10020000,
  "resMsg": "请求成功",
  "data": {
    "update": true
  }
}
2021-09-08 16:14:51.785 DEBUG 4380 --- [nio-8080-exec-9] c.l.d.mapper.UserMapper.updateById       : ==>  Preparing: UPDATE user SET username=?, password=?, tel_new=? WHERE id=? AND deleted=0
2021-09-08 16:14:51.785 DEBUG 4380 --- [nio-8080-exec-9] c.l.d.mapper.UserMapper.updateById       : ==> Parameters: 小道科(String), 123456(String), 112(String), 1435514618490388480(Long)
2021-09-08 16:14:51.787 DEBUG 4380 --- [nio-8080-exec-9] c.l.d.mapper.UserMapper.updateById       : <==    Updates: 1

DELETE请求

代码语言:javascript
复制
func TestHttp5(t *testing.T) {
 resq, err := http.NewRequest("DELETE","http://localhost:8080/user/1435514618490388480",nil)
 if err != nil {
  log.Fatalf("error: %v", err)
  return
 }
 res, err := http.DefaultClient.Do(resq)
 if err != nil {
  log.Fatalf("did not connect: %v", err)
  return
 }
 defer func(Body io.ReadCloser) {
  err := Body.Close()
  if err != nil {
   log.Fatalf("did not close: %v", err)
   return
  }
 }(res.Body)
 if res.StatusCode == 200 {
  log.Printf("success")
  name, err := ioutil.ReadAll(res.Body)
  if err != nil {
   log.Fatalf("could not greet: %v", err)
  }
  log.Printf("Greeting: %s", name)
 }
}

结果:

代码语言:javascript
复制
2021/09/08 16:14:14 Greeting:
{
  "status": 10020000,
  "resMsg": "请求成功",
  "data": {
    "remove": true
  }
}
2021-09-08 16:14:14.400 DEBUG 4380 --- [nio-8080-exec-5] c.l.d.mapper.UserMapper.deleteById       : ==>  Preparing: UPDATE user SET deleted=1 WHERE id=? AND deleted=0
2021-09-08 16:14:14.400 DEBUG 4380 --- [nio-8080-exec-5] c.l.d.mapper.UserMapper.deleteById       : ==> Parameters: 1435514618490388480(Long)
2021-09-08 16:14:14.404 DEBUG 4380 --- [nio-8080-exec-5] c.l.d.mapper.UserMapper.deleteById       : <==    Updates: 1
  1. 如果需要自定义请求头、自定义方法,都可以使用http.NewRequesthttp.DefaultClient.Do(resq)来完成。
  2. 如需设置Header参数,可采用resq.Header.Set("Content-Type", "application/json")(参考POST请求)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 博思奥园 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 接口定义
    • 实体类
      • 接口
      • Http请求调用
        • 基本的GET请求
          • GET请求 携带参数
            • 基本的POST请求(form)
              • POST请求(body)
                • PUT 请求
                  • DELETE请求
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档