在使用go-zero创建api成功,但访问失败,报400错误

本文记录了解决使用curl访问Go服务API时遇到的400错误、Content-Type错误和字段未设置问题的过程。问题源于CMD不识别单引号、Content-Type拼写错误以及JSON格式传递参数时的转义字符问题。最终通过修改curl命令,成功访问到API并获取到了预期的响应。
摘要由CSDN通过智能技术生成

问题描述

最近在尝试使用开源框架go-zero,
userapi已成功运行在8888端口,尝试访问api时报错:

C:\Users\Carino>curl -i -X POST http://127.0.0.1:8888/user/login -H 'Conten-Type: application/json' -d '{"username":"666", "password":"123456"}'
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Trace-Id: 9dd840357001d2220f7559f1c24269b2
Date: Wed, 23 Feb 2022 09:01:56 GMT
Content-Length: 26

field username is not set
curl: (6) Could not resolve host: application
curl: (3) unmatched close brace/bracket in URL position 16:
password:123456}'

解决办法

其实是在cmd里输入curl命令时,因为参照demo里格式输入的,cmd不识别导致,在cmd里输入curl命令需要注意,cmd不支持单引号,因此要将单引号换成双引号,另外,对于双引号里还有双引号,需要对内部的双引号加转义字符"",最后,正确的名称参数格式如下:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "{ \"username\":\"666\", \"password\":\"123456\" }"
访问结果:

D:\go 练习\book\service>curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "{ \"username\":\"666\", \"password\":\"123456\" }"
HTTP/1.1 200 OK
Content-Type: application/json
X-Trace-Id: 172c247d76adbb27efda8e386479970b
Date: Thu, 24 Feb 2022 03:17:20 GMT
Content-Length: 252

{"ind":1,"name":"小明","gender":"男","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDU2Nzk4NDAsImlhdCI6MTY0NTY3MjY0MCwidXNlcklkIjoxfQ.F2wg1LnNZlO8uGaLHpX_1qhghAmaFyMYrl-rD3KcLQc","accessExpire":1645679840,"refreshAfter":1645676240}

以下是问题解决过程,有些曲折,而且打脸

问题分析

从上面的报错信息可以看出:

  1. 报400错误,应该是客户端的问题。
  2. 请求的数据类型是application/json,但是返回的却是text/plain
  3. 提示username没有被正确设置
  4. 提示输入curl命令时,参数的格式不是很正确.大括号没有对齐.

解决思路

首先,从最简单的错误开始解决。从上面几个错误提示来看,很有可能是输入curl命令时,因为是在CMD的环境里,导致格式上的错误。需要找到一种可靠的输入curl命令的方式。
既然之前在学习创建微服务案例时能成功创建api,为什么这次不行呢?
通过查看api关联的数据表发现:
在这里插入图片描述
在这个表里,只有一个用户,他的属性并没有username,而是name,并且name的值也并不等于666,反而是number的属性值。
另外,通过查阅curl资料,发现,在输入-d参数时,有格式上的要求:

$ curl -d'login=emma&password=123'-X POST https://google.com/login

或者

$ curl -d 'login=emma' -d 'password=123' -X POST https://google.com/login

那么

接下来修改命令再试试:
curl -i -X POST http://127.0.0.1:8888/user/login -H 'Conten-Type: application/json' -d 'number=666&password=123456'
报错:

C:\Users\Carino>curl -i -X POST http://127.0.0.1:8888/user/login -H 'Conten-Type: application/json' -d 'number=666&password=123456'
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Trace-Id: e97671d6cdcf11d3b61b9c65ee9adce5
Date: Wed, 23 Feb 2022 09:30:28 GMT
Content-Length: 26

field username is not set
curl: (6) Could not resolve host: application
'password' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

关于curl: (6) Could not resolve host: application

但还是没有头绪,在查找问题curl: (6) Could not resolve host: application找到以下有用的回答:

https://bbs.huaweicloud.com/blogs/299447

意思是说CMD不识别单引号引起的,将命令里的单引号换成双引号,再试试:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Conten-Type: application/json" -d "number=666&password=123456"
报错:

C:\Users\Carino>curl -i -X POST http://127.0.0.1:8888/user/login -H "Conten-Type: application/json" -d "number=666&password=123456"
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Trace-Id: 9b063b705bb247443db1b4385b32505e
Date: Thu, 24 Feb 2022 01:32:11 GMT
Content-Length: 26

field username is not set

至少,将问题curl: (6) Could not resolve host: application解决了!

关于field username is not set

接下来,将问题聚焦在field username is not set上面:
看来问题可能处在user的api里使用username作为属性,而不是与数据库保持一致使用user作为属性,检查下user的api相关的文件,
首先在user.api文件里,我们发现有使用username:

type (
	LoginReq {
		Username string `json:"username"`
		Password string `json:"password"`
	}

	LoginReply {
		Id           int64  `json:"ind"`
		Name         string `json:"name"`
		Gender       string `json:"gender"`
		AccessToken  string `json:"accessToken"`
		AccessExpire int64  `json:"accessExpire"`
		RefreshAfter int64  `json:"refreshAfter"`
	}
)
service user-api {
	@handler login
	post /user/login (LoginReq) returns (LoginReply)
}

发现关于LoginReq的属性定义有两个,一个是username,另一个是password,而在我们执行curl命令时,却使用了number而不是username,接下来,将其更改过来试下:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Conten-Type: application/json" -d "username=666&password=123456"
依然报错:

C:\Users\Carino>curl -i -X POST http://127.0.0.1:8888/user/login -H "Conten-Type: application/json" -d "username=666&password=123456"
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Trace-Id: 76bd74b37ce52149527a610044593f9f
Date: Thu, 24 Feb 2022 01:40:35 GMT
Content-Length: 26

field username is not set

既然请求的参数没有错,难道是关于LoginReply里没有定义好username的属性。

经过仔细观察,发现命令里将Content-Type写成了Conten-Type

修改命令,再试:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "username=666&password=123456"
继续报错:

D:\go 练习\book\service>curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "username=“小明”&password=123456"
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Trace-Id: b5c69e832a00e5e406e4c151c521f4ae
Date: Thu, 24 Feb 2022 02:26:57 GMT
Content-Length: 107

string: `username=������&password=123456`, error: `invalid character 'u' looking for beginning of value`

关于错误error: `invalid character 'u' looking for beginning of object key string

难道还是传参错误,改成最开始的形式:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "{ "username":"666", "password":"123456" }"
错误类型一样:

D:\go 练习\book\service>curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "{ "username":"666", "password":"123456" }"
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
X-Content-Type-Options: nosniff
X-Trace-Id: f6599c4ee64813cdc0fb310ef67b7426
Date: Thu, 24 Feb 2022 02:35:16 GMT
Content-Length: 119

string: `{ username:666, password:123456 }`, error: `invalid character 'u' looking for beginning of object key string`

查阅了相关资料,显示可能是编码错误,在-H参数里加上编码方式,再试试:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json;charset=UTF-8" -d "username=666&password=123456"
依然报同样的错误,看来是-d的参数解析错误导致!
使用powershell工具运行同样的命令,显示如下:

PS C:\Users\Carino> curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "username=666&password=123456"
Invoke-WebRequest : 无法绑定参数“Headers”。无法将“System.String”类型的“Content-Type: application/json”值转换为“System.Collections.IDictionary”类型。
所在位置 行:1 字符: 53
+ ... 127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "use ...
+                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Invoke-WebRequest],ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

继续查阅,有用的信息如下:

https://www.jianshu.com/p/2a59107f743b
https://blog.csdn.net/zhlzdjdj/article/details/104087409

关于问题2请求的数据类型是application/json,但是返回的却是text/plain

https://www.jianshu.com/p/3366dec071af
https://www.cnblogs.com/dede0753/p/12531856.html

惊喜来的太突然

综合上面的分析,判断应该是在使用curl时,-d的参数传入的格式有问题,仿照原始的demo里给的样例,对参数里双引号内部的双引号增加转移字符,如下:
curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "{ \"username\":\"666\", \"password\":\"123456\" }"
运行结果如下:

D:\go 练习\book\service>curl -i -X POST http://127.0.0.1:8888/user/login -H "Content-Type: application/json" -d "{ \"username\":\"666\", \"password\":\"123456\" }"
HTTP/1.1 200 OK
Content-Type: application/json
X-Trace-Id: 172c247d76adbb27efda8e386479970b
Date: Thu, 24 Feb 2022 03:17:20 GMT
Content-Length: 252

{"ind":1,"name":"小明","gender":"男","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2NDU2Nzk4NDAsImlhdCI6MTY0NTY3MjY0MCwidXNlcklkIjoxfQ.F2wg1LnNZlO8uGaLHpX_1qhghAmaFyMYrl-rD3KcLQc","accessExpire":1645679840,"refreshAfter":1645676240}

访问api成功!

总结:

  1. cmd中无法识别单引号,对于参数里有双引号内部还有双引号的,需要对内部的双引号进行转义,否则会将双引号作为参数的一部分而导致错误;
    2.上面所有的问题都是在cmd里输入curl命令导致,其实只要api服务正常跑起来,应该是能访问的,也会抛出清晰的error提示,除非是压根就没有访问到服务,像这次这样,输入命令格式问题。所以, 编写代码时一定要细心!!!其实在写api代码时是非常细心的,是没有什么错误的,结果在输入命令的时候疏忽了,有些打脸;
  2. 如果能在linux环境下开发,尽量在linux环境下开发。目前在Windows下开发只是权宜之计,后面生产阶段还是会转linux。
  3. 关于报错field username is not set,是因为将header参数里的Content-Type错写成了Conten-Type导致。
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值