来自 CURL 和浏览器的不同服务器行为
Different server behavior from CURL and browser
当我使用 CURL 和从浏览器发出登录请求时,我的服务器表现不同。
执行以下 curl 请求时:
curl -i -X POST 'http://localhost:8080/login' -d 'username=fred&password=blah' -H 'content-type: application/x-www-form-urlencoded'
我得到以下形式的预期结果:
然而,当从浏览器表单执行相同(或者我认为)请求时,我在浏览器调试器中看到以下结果
用于发出请求的表单代码如下所示
<form action="localhost:8080/login" method="POST">
<input type="text" name="username" placeholder="Username">
<input type="text" name="password" placeholder="Password">
<input type="submit" id="sign_in" value="Sign In">
</form>
我认为这不是请求来源的问题,因为我设置了 Access-Controll-Allow-Origin': *
。
服务器的完整代码可以找到here. The code of the client here。
我没主意了。什么可能导致此问题?
编辑:正如@Günter Zöchbauer 在下面的评论中所建议的,通常需要通过 HttpRequest 进行此类表单提交。我想添加一个带有现成解决方案的答案,然后直接进入另一个问题。
相关html:
<form id="login_form" action="/login" method="POST" enctype="application/x-www-form-urlencoded">
<input type="text" name="username" placeholder="Username">
<input type="text" name="password" placeholder="Password">
<input type="submit" id="sign_in" value="Sign In" on-click="{{submitLogin}}">
</form>
相关飞镖代码:
/* Login box */
login_form = querySelector('#login_form');
login_form.onSubmit.listen(submitLogin);
和
/* Login code */
void submitLogin(Event e){
e.preventDefault();
FormElement form = e.target as FormElement;
print('inside of submitLogin');
Uri loginUri = new Uri(scheme: 'http',
host: 'localhost',
port: 8080,
path: 'login');
print(loginUri);
var request = new HttpRequest();
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
request.request(
loginUri.toString(),
method: form.method,
sendData: new FormData(form)
).then(onDataLoaded);
}
void onDataLoaded(HttpRequest req){
String response = req.responseText;
print(response);
//TODO: do visual confiramtion of login
}
当比较来自原始请求(有效)的 CURL 和上面代码完成的请求时,我注意到 Content-Type
是不同的。
我尝试以我所知道的所有方式强制执行内容类型,但它总是出现这样的情况。
curl "http://localhost:8080/login" -H "Origin: http://localhost:8080" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4" -H "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.0 (Dart) Safari/537.36" -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZ1seZo8pq0PZt3Fg" -H "Accept: */*" -H "Referer: http://localhost:8080/" -H "Connection: keep-alive" --data-binary "------WebKitFormBoundaryZ1seZo8pq0PZt3Fg"^
"Content-Disposition: form-data; name=""username"""^
"fred"^
"------WebKitFormBoundaryZ1seZo8pq0PZt3Fg"^
"Content-Disposition: form-data; name=""password"""^
"blah"^
"------WebKitFormBoundaryZ1seZo8pq0PZt3Fg--"^
"" --compressed
而不是。
curl "http://localhost:8080/login" -H "Origin: http://localhost:8080" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4" -H "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.0 (Dart) Safari/537.36" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" -H "Cache-Control: max-age=0" -H "Referer: http://localhost:8080/" -H "Connection: keep-alive" --data "username=fred&password=blah" --compressed
你在action
属性中的URL是相对的,这意味着它附加到当前主机名。因此,通过添加 http://
将其更改为绝对 URL,或者如果您已经在 localhost:8080
.
上,则将其更改为 /login
这个答案与问题的第二部分有关(见编辑)。我在文档中的任何地方都找不到现成的示例代码。这就是为什么我在下面添加工作代码作为答案。如果您找到更优雅的方式从表单中获取数据,请在此下方发表评论 post。
HTML部分
<form id="login_form" action="/login" method="POST" enctype="application/x-www-form-urlencoded">
<input type="text" name="username" placeholder="Username">
<input type="text" name="password" placeholder="Password">
<input type="submit" id="sign_in" value="Sign In">
</form>
飞镖代码
订阅活动
login_form = querySelector('#login_form');
login_form.onSubmit.listen(submitLogin);
事件处理程序
/* Login code */
void submitLogin(Event e){
e.preventDefault();
FormElement form = e.target as FormElement;
print('inside of submitLogin');
Uri loginUri = new Uri(scheme: 'http',
host: 'localhost',
port: 8080,
path: 'login');
InputElement username = querySelector('[name="username"]');
InputElement password = querySelector('[name="password"]');
Map dataFromForm = {'username':username.value.toString(),'password':password.value.toString()};
print(loginUri);
HttpRequest.postFormData(loginUri.toString(), dataFromForm)
.then(onDataLoaded);
}
void onDataLoaded(HttpRequest req){
String response = req.responseText;
print(response);
//TODO: do visual
当我使用 CURL 和从浏览器发出登录请求时,我的服务器表现不同。
执行以下 curl 请求时:
curl -i -X POST 'http://localhost:8080/login' -d 'username=fred&password=blah' -H 'content-type: application/x-www-form-urlencoded'
我得到以下形式的预期结果:
然而,当从浏览器表单执行相同(或者我认为)请求时,我在浏览器调试器中看到以下结果
用于发出请求的表单代码如下所示
<form action="localhost:8080/login" method="POST">
<input type="text" name="username" placeholder="Username">
<input type="text" name="password" placeholder="Password">
<input type="submit" id="sign_in" value="Sign In">
</form>
我认为这不是请求来源的问题,因为我设置了 Access-Controll-Allow-Origin': *
。
服务器的完整代码可以找到here. The code of the client here。
我没主意了。什么可能导致此问题?
编辑:正如@Günter Zöchbauer 在下面的评论中所建议的,通常需要通过 HttpRequest 进行此类表单提交。我想添加一个带有现成解决方案的答案,然后直接进入另一个问题。 相关html:
<form id="login_form" action="/login" method="POST" enctype="application/x-www-form-urlencoded">
<input type="text" name="username" placeholder="Username">
<input type="text" name="password" placeholder="Password">
<input type="submit" id="sign_in" value="Sign In" on-click="{{submitLogin}}">
</form>
相关飞镖代码:
/* Login box */
login_form = querySelector('#login_form');
login_form.onSubmit.listen(submitLogin);
和
/* Login code */
void submitLogin(Event e){
e.preventDefault();
FormElement form = e.target as FormElement;
print('inside of submitLogin');
Uri loginUri = new Uri(scheme: 'http',
host: 'localhost',
port: 8080,
path: 'login');
print(loginUri);
var request = new HttpRequest();
request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
request.request(
loginUri.toString(),
method: form.method,
sendData: new FormData(form)
).then(onDataLoaded);
}
void onDataLoaded(HttpRequest req){
String response = req.responseText;
print(response);
//TODO: do visual confiramtion of login
}
当比较来自原始请求(有效)的 CURL 和上面代码完成的请求时,我注意到 Content-Type
是不同的。
我尝试以我所知道的所有方式强制执行内容类型,但它总是出现这样的情况。
curl "http://localhost:8080/login" -H "Origin: http://localhost:8080" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4" -H "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.0 (Dart) Safari/537.36" -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZ1seZo8pq0PZt3Fg" -H "Accept: */*" -H "Referer: http://localhost:8080/" -H "Connection: keep-alive" --data-binary "------WebKitFormBoundaryZ1seZo8pq0PZt3Fg"^
"Content-Disposition: form-data; name=""username"""^
"fred"^
"------WebKitFormBoundaryZ1seZo8pq0PZt3Fg"^
"Content-Disposition: form-data; name=""password"""^
"blah"^
"------WebKitFormBoundaryZ1seZo8pq0PZt3Fg--"^
"" --compressed
而不是。
curl "http://localhost:8080/login" -H "Origin: http://localhost:8080" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4" -H "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.0 (Dart) Safari/537.36" -H "Content-Type: application/x-www-form-urlencoded" -H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" -H "Cache-Control: max-age=0" -H "Referer: http://localhost:8080/" -H "Connection: keep-alive" --data "username=fred&password=blah" --compressed
你在action
属性中的URL是相对的,这意味着它附加到当前主机名。因此,通过添加 http://
将其更改为绝对 URL,或者如果您已经在 localhost:8080
.
/login
这个答案与问题的第二部分有关(见编辑)。我在文档中的任何地方都找不到现成的示例代码。这就是为什么我在下面添加工作代码作为答案。如果您找到更优雅的方式从表单中获取数据,请在此下方发表评论 post。
HTML部分
<form id="login_form" action="/login" method="POST" enctype="application/x-www-form-urlencoded">
<input type="text" name="username" placeholder="Username">
<input type="text" name="password" placeholder="Password">
<input type="submit" id="sign_in" value="Sign In">
</form>
飞镖代码 订阅活动
login_form = querySelector('#login_form');
login_form.onSubmit.listen(submitLogin);
事件处理程序
/* Login code */
void submitLogin(Event e){
e.preventDefault();
FormElement form = e.target as FormElement;
print('inside of submitLogin');
Uri loginUri = new Uri(scheme: 'http',
host: 'localhost',
port: 8080,
path: 'login');
InputElement username = querySelector('[name="username"]');
InputElement password = querySelector('[name="password"]');
Map dataFromForm = {'username':username.value.toString(),'password':password.value.toString()};
print(loginUri);
HttpRequest.postFormData(loginUri.toString(), dataFromForm)
.then(onDataLoaded);
}
void onDataLoaded(HttpRequest req){
String response = req.responseText;
print(response);
//TODO: do visual