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; 
}

接着在入口页面中调用上述封装的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; 
  } 
} 
}

分析模块源码可知,通过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;                                                                                 
      }         

传输选项设置成功后,调用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); 
}

在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)); 
  } 
}
分享
微博
QQ
微信
回复
2024-05-27 22:15:09
相关问题
如何设置发起网络请求的权限
402浏览 • 1回复 待解决
http请求支持patch方法
1965浏览 • 1回复 待解决
求告知如何发起HTTP请求
335浏览 • 1回复 待解决
http request 请求不到接口数据
4793浏览 • 1回复 待解决
使用http请求网络地址
713浏览 • 1回复 待解决
网络请求创建后,持久化问题
519浏览 • 1回复 待解决
网络请求-GET请求传参
321浏览 • 1回复 待解决
rcp模块能力发起post请求
1060浏览 • 1回复 待解决
HTTP请求使用同SESSIONID
299浏览 • 1回复 待解决
http 请求直报 2300058
1556浏览 • 0回复 待解决
Web组件如何发起一个下载任务
312浏览 • 1回复 待解决