HTTP请求Demo,通过createHttp方法创建一个请求任务,再通过request方法发起网络请求

通过createHttp方法创建一个请求任务,再通过request方法发起网络请求。

HarmonyOS
2024-05-26 17:33:40
浏览
收藏 0
回答 1
回答 1
按赞同
/
按时间
社恐的小美

使用的核心API

http.createHttp

核心代码解释

首先在HttpUtil.ets中调用createHttp方法创建一个请求任务,再通过request方法发起网络请求。该方法支持三个参数:url、options以及callback回调,其中options可以设置请求方法、请求头以及超时时间等。

// HttpUtil.ets 
import http from '@ohos.net.http'; 
export default async function httpGet(url: string) { 
 if (!url) { 
   return undefined; 
} 
 let request = http.createHttp(); 
 let options = { 
   method: http.RequestMethod.GET, 
   header: { 'Content-Type': 'application/json' }, 
   readTimeout: CommonConstant.READ_TIMEOUT, 
   connectTimeout: CommonConstant.CONNECT_TIMEOUT 
} as http.HttpRequestOptions; 
 let result = await request.request(url, options); 
 return result; 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

接着在入口页面中调用上述封装的httpGet方法请求指定网址,将请求得到的内容嵌入到Web组件中。

// WebPage.ets 
import http from '@ohos.net.http'; 
... 
@Entry 
@Component 
struct WebPage { 
 @State webVisibility: Visibility = Visibility.Hidden; 
... 
 build() { 
   Column() { 
    ... 
  } 
} 
​ 
 async onRequest() { 
   if (this.webVisibility === Visibility.Hidden) { 
     this.webVisibility = Visibility.Visible; 
     try { 
       let result = await httpGet(this.webSrc); 
       if (result && result.responseCode === http.ResponseCode.OK) { 
         this.controller.clearHistory(); 
         this.controller.loadUrl(this.webSrc); 
      }  
    } catch (error) { 
       promptAction.showToast({ 
         message: $r('app.string.http_response_error') 
      }) 
    } 
  } else { 
     this.webVisibility = Visibility.Hidden; 
  } 
} 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

分析模块源码可知,通过request方法建立请求后,模块底层首先会调用三方库libcurl中的curl_easy_init初始化一个简单会话。初始化完成后,接着调用curl_easy_setopt方法设置传输选项。其中CURLOPT_URL用于设置请求的URL地址,对应request中的url参数;CURLOPT_WRITEFUNCTION可以设置一个回调,保存接收的数据;CURLOPT_HEADERDATA支持设置回调,在回调中保存响应头数据。

// http_exec.cpp 
bool HttpExec::RequestWithoutCache(RequestContext *context) 
{ 
   if (!staticVariable_.initialized) { 
       NETSTACK_LOGE("curl not init"); 
       return false; 
  } 
   auto handle = curl_easy_init(); 
  ... 
   if (!SetOption(handle, context, context->GetCurlHeaderList())) { 
       NETSTACK_LOGE("set option failed"); 
       return false; 
  } 
  ... 
   return true; 
} 
... 
bool HttpExec::SetOption(CURL *curl, RequestContext *context, struct curl_slist *requestHeader) 
{ 
   const std::string &method = context->options.GetMethod(); 
   if (!MethodForGet(method) && !MethodForPost(method)) { 
       NETSTACK_LOGE("method %{public}s not supported", method.c_str()); 
       return false; 
  } 
   if (context->options.GetMethod() == HttpConstant::HTTP_METHOD_HEAD) { 
       NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_NOBODY, 1L, context); 
  } 
   // 设置请求URL 
   NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_URL, context->options.GetUrl().c_str(), context); 
  ... 
   // 设置CURLOPT_WRITEFUNCTION传输选项,OnWritingMemoryBody为回调函数 
   NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_WRITEFUNCTION, OnWritingMemoryBody, context); 
   NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_WRITEDATA, context, context); 
   // 在OnWritingMemoryHeader写入响应头数据 
   NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADERFUNCTION, OnWritingMemoryHeader, context); 
   NETSTACK_CURL_EASY_SET_OPTION(curl, CURLOPT_HEADERDATA, context, context); 
  ... 
   return true; 
} 
... 
#define NETSTACK_CURL_EASY_SET_OPTION(handle, opt, data, asyncContext)                                    
   do {             
       CURLcode result = curl_easy_setopt(handle, opt, data);                                            
       if (result != CURLE_OK) {                                                                         
           const char *err = curl_easy_strerror(result);                                                 
           NETSTACK_LOGE("Failed to set option: %{public}s, %{public}s %{public}d", #opt, err, result);  
          (asyncContext)->SetErrorCode(result);                                                         
           return false;                                                                                 
      }         
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.

传输选项设置成功后,调用curl_multi_perform执行传输请求,并通过curl_multi_info_read查询处理句柄是否有消息返回,最后进入HandleCurlData方法处理返回数据。

// http_exec.cpp 
void HttpExec::SendRequest() 
{ 
  ... 
   do { 
      ... 
       auto ret = curl_multi_perform(staticVariable_.curlMulti, &runningHandle); 
      ... 
  } while (runningHandle > 0); 
} 
... 
void HttpExec::ReadResponse() 
{ 
   CURLMsg *msg = nullptr; /* NOLINT */ 
   do { 
      ... 
       msg = curl_multi_info_read(staticVariable_.curlMulti, &leftMsg); 
       if (msg) { 
           if (msg->msg == CURLMSG_DONE) { 
               HandleCurlData(msg); 
          } 
      } 
  } while (msg); 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

在HandleCurlData函数中调用ParseHeaders函数将上面回调写入的响应头解析出来,其中响应头中会携带客户端和服务端支持的最高网络协议,如果是HTTP/2表示支持HTTPS加密传输。

// http_exec.cpp 
bool HttpExec::GetCurlDataFromHandle(CURL *handle, RequestContext *context, CURLMSG curlMsg, CURLcode result) 
{ 
  ... 
   context->response.ParseHeaders(); 
   return true; 
} 
// http_response.cpp 
void HttpResponse::ParseHeaders() 
{ 
   std::vector<std::string> vec = CommonUtils::Split(rawHeader_, HttpConstant::HTTP_LINE_SEPARATOR); 
   for (const auto &header : vec) { 
       if (CommonUtils::Strip(header).empty()) { 
           continue; 
      } 
       auto index = header.find(HttpConstant::HTTP_HEADER_SEPARATOR); 
       if (index == std::string::npos) { 
           header_[CommonUtils::Strip(header)] = ""; 
           NETSTACK_LOGI("HEAD: %{public}s", CommonUtils::Strip(header).c_str()); 
           continue; 
      } 
       header_[CommonUtils::ToLower(CommonUtils::Strip(header.substr(0, index)))] = 
           CommonUtils::Strip(header.substr(index + 1)); 
  } 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
分享
微博
QQ
微信
回复
2024-05-27 22:15:09
相关问题
如何设置发起网络请求的权限
990浏览 • 1回复 待解决
HarmonyOS 如何发起网络接口请求
781浏览 • 1回复 待解决
http请求支持patch方法
3036浏览 • 1回复 待解决
HarmonyOS http网络请求封装的Demo
931浏览 • 1回复 待解决
求告知如何发起HTTP请求
1300浏览 • 1回复 待解决
HarmonyOS 如何取消一个HTTP请求
703浏览 • 1回复 待解决
HarmonyOS 推荐一个http请求
861浏览 • 1回复 待解决
HarmonyOS 网络发起多个并发请求
929浏览 • 1回复 待解决
http request 请求不到接口数据
6079浏览 • 1回复 待解决
使用http请求网络地址
1736浏览 • 1回复 待解决