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)

相關文章
相關標籤/搜索