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

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

作者:lomtom

个人网站:lomtom.top

个人公众号:博思奥园

你的支持就是我最大的动力。

Go系列:

  1. Go(一)基础入门
  2. Go(二)结构体
  3. Go(三)Go配置文件
  4. Go(四)Redis操作
  5. Go(五)Go不知道怎么用Gorm?
  6. Go(六)来来来,教你怎么远程调用

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

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

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

接口定义

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

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

例如:

1
2
3
4
5
bash复制代码GET 查询列表
GET 查询单个用户
POST 保存用户
PUT 修改单个用户
DELETE 删除单个用户

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码@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;
}
}

接口

其次,编写相应接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
java复制代码@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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
json复制代码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后面进行拼接,当然也可以采用以下方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
json复制代码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注解,否则将调用失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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)发起请求即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求)

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

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

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

接口定义

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

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

例如:

1
2
3
4
5
bash复制代码GET 查询列表
GET 查询单个用户
POST 保存用户
PUT 修改单个用户
DELETE 删除单个用户

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码@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;
}
}

接口

其次,编写相应接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
java复制代码@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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
json复制代码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后面进行拼接,当然也可以采用以下方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
json复制代码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注解,否则将调用失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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)发起请求即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求)

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

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

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

接口定义

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

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

例如:

1
2
3
4
5
bash复制代码GET 查询列表
GET 查询单个用户
POST 保存用户
PUT 修改单个用户
DELETE 删除单个用户

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码@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;
}
}

接口

其次,编写相应接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
java复制代码@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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
json复制代码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后面进行拼接,当然也可以采用以下方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
json复制代码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注解,否则将调用失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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)发起请求即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求)

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

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

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

接口定义

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

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

例如:

1
2
3
4
5
bash复制代码GET 查询列表
GET 查询单个用户
POST 保存用户
PUT 修改单个用户
DELETE 删除单个用户

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
java复制代码@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;
}
}

接口

其次,编写相应接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
java复制代码@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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
json复制代码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后面进行拼接,当然也可以采用以下方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
json复制代码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注解,否则将调用失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码// 基本的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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
bash复制代码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)发起请求即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
go复制代码// 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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
go复制代码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)
}
}

结果:

1
2
3
4
5
6
7
8
9
10
11
bash复制代码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请求)

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%