问题描述
最近在尝试使用开源框架go-zero
,
user
的api
已成功运行在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}
以下是问题解决过程,有些曲折,而且打脸
问题分析
从上面的报错信息可以看出:
- 报400错误,应该是客户端的问题。
- 请求的数据类型是
application/json
,但是返回的却是text/plain
- 提示
username
没有被正确设置 - 提示输入
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成功!
总结:
cmd
中无法识别单引号,对于参数里有双引号内部还有双引号的,需要对内部的双引号进行转义,否则会将双引号作为参数的一部分而导致错误;
2.上面所有的问题都是在cmd
里输入curl
命令导致,其实只要api
服务正常跑起来,应该是能访问的,也会抛出清晰的error提示,除非是压根就没有访问到服务,像这次这样,输入命令格式问题。所以, 编写代码时一定要细心!!!其实在写api
代码时是非常细心的,是没有什么错误的,结果在输入命令的时候疏忽了,有些打脸;- 如果能在
linux
环境下开发,尽量在linux
环境下开发。目前在Windows下开发只是权宜之计,后面生产阶段还是会转linux。 - 关于报错
field username is not set
,是因为将header参数里的Content-Type
错写成了Conten-Type
导致。