http请求那点事

前言

此次项目使用了angular + 第三方c++http服务对接。没有了脱离了熟悉的springboot,刚加接近原生。也遇到了不少问题。php

拒绝链接

照着第三方库启动c++服务后,在本机测试能够请求到
image.pnghtml

可是使用其余电脑,把localhost改为服务器ip就没法请求到
image.png
经过去看github项目上的issue看到,你们也遇到了如此问题,最后你们的解决办法是以管理员身份运行vs而且将代码从nginx

web::http::experimental::listener::http_listener getStatusListener(L"http://127.0.0.1:8015/getStatus");

改为c++

web::uri_builder uri;
    uri.set_scheme(U("http"));
    uri.set_host(U("+"));
    uri.set_port(U("8015"));
    uri.set_path(U("/getStatus"));
    web::http::experimental::listener::http_listener getStatusListener(uri.to_uri());

具体缘由也没有具体说明(或者我没有看懂)。问了老师后,老师建议配置一下nginx解决。
经过此次配置nginx,理解了nginx本质上仍是服务器,原来觉得nginx只负责端口转发,springboot起服务做用的是tomcat。就如thinphp的apache同样。git

image.png
经过nginx对请求的转发,对于c++服务来讲nginx对他的请求就是localhost的地址。从而解决问题。
在后台添加了一个post接口,用于启动捕获数据。使用API Tester插件测试接口。
image.png
可是在启动前台单元测试进行对接的时候,请求一样的地址,发生了请求错误。
image.png
更加奇怪的是,他连续对同一地址请求了两次,而我只操做了一次。第二次返回了200,可是服务器端也没有响应打印信息。第一次请求的CORS error报错在写上一个GET请求接口的时候也遇到过,这是由于先后台不一样源,违反了同源策略,解决办法是在相应头上加入Access-Control-Allow-Origin:*字段,容许跨域访问。github

// 响应
web::http::http_response response(web::http::status_codes::OK);
response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
response.set_body(jsonResponseFinal);
request.reply(response);

可是再遇到相同问题,这个解决办法没有成功。
如今的问题是
1.为何一样的错误解决方法只适用于GET请求而不适用与POST请求?
2.而且为何会请求了两次?
3.为何API Tester测试没有问题?
带着这些问题问了学长。
学长看了之后发现第二次返回200的请求实际上是OPTIONS请求。
image.png
什么是OPTIONS请求呢。咱们能够把OPTIONS请求当作先遣队。OPTIONS请求的主要用途有两个
一是获取服务器支持的HTTP请求方法;
二是用来检查服务器的性能。web

那些可能会操做数据库的请求(除GET请求外),都会使用 OPTIONS 发起一个预检请求(preflight request),从而获知服务端是否容许该跨域请求。服务器确认容许以后,才发起实际的 HTTP 请求。
Preflighted Requests是CORS中一种透明服务器验证机制。预检请求首先须要向另一个域名的资源发送一个 HTTP OPTIONS 请求头,其目的就是为了判断实际发送的请求是不是安全的。
下面的状况须要进行预检:
非简单请求,好比使用Content-Type 为 application/xml 或 text/xml 的 POST 请求;(什么是简单请求,什么是非简单请求,请移步阮一峰的 跨域资源共享 CORS 详解

下面借用MDN的图来更直观的看一下spring

image.png
因此解决也就是在options相应头加入容许请求。数据库

web::http::experimental::listener::http_listener startCaptureListener(L"http://127.0.0.1:8015/startCapture");
startCaptureListener.support(web::http::methods::POST, [&](web::http::http_request request) {
        this->startCapture(request);
});
startCaptureListener.support(web::http::methods::OPTIONS, [&](web::http::http_request request) {
        this->allow(request);
});

void YzHttp::HttpService::allow(web::http::http_request request) {
    web::http::http_response response(web::http::status_codes::OK);
    response.headers().add(U("Access-Control-Allow-Origin"), U("*"));
    response.headers().add(U("Access-Control-Allow-Methods"), U("POST"));
    response.headers().add(U("Access-Control-Allow-Headers"), U("Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"));
    request.reply(response);
}

问题解决。
最后一个问题,为何用API Tester测试能经过呢。可能没法模拟真正的浏览器访问吧。apache

总结

经过构建c++http服务,使用更加原生的代码。更能知道本身有哪些http知识不清楚。而springboot框架为咱们作好了一切,也让咱们没机会接触这些知识。
感谢黄庭祥学长在我解决问题过程当中给予的帮助。

参考链接

Server does not work from public IP, but localhost or other SDKs are fine
为何会有OPTIONS请求
跨源资源共享(CORS)