欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 运维知识 > android >内容正文

android

http请求过程 android,android http网络请求回顾 -凯发k8官方网

发布时间:2024/10/8 android 0 豆豆
凯发k8官方网 收集整理的这篇文章主要介绍了 http请求过程 android,android http网络请求回顾 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

1.http协议了解

http是一种应用层的协议,底层通过tcp来进行可靠的数据传输。http是基于tcp的应用层协议,它在更高的层次封装了tcp的使用细节,使网络请求更加易用,tcp连接是因特网基于流的一种可靠连接,它为http提供了一条可靠的比特传输管道。从tcp连接一端填入的字节会从另一端以原有的顺序、正确的传送过来。

http的7种请求方式

get

post

delete

put

head

trace

potions

[图片上传失败...(image-aa15fa-1517135394572)]

http报文格式解析

不同的请求方式,它们的请求格式也是不一样的,请求格式也就是报文格式。 通常来说一个http请求报文由 请求行(request line)、请求头部(head)、空行、请求数据 4个部分组成。

[图片上传失败...(image-fbc600-1517135394572)]

请求行

报文的第一行就是请求行,这一行说明了这段报文以什么方式请求,包含了http的版本号等一些协议信息。

请求头部

请求头部是以 key:value的形式来说明请求数据的,这里面说明了请求服务器的一些host,content-tye,encoding的一些说明。

请求数据

post请求的方式才会有请求数据,如果请求是以post提交过来,那么这里面就会有post的请求数据,可以文本形式或者二进制数据根据你请求post提交的数据类型决定。

get 请求报文格式

www.jinweime.com?id=2

这个是一个典型的get请求,get请求的参数会跟在url后面。问号后面作为第一个参数,以&进行参数拼接。

http请求协议如下

get /?id=2 http/1.1

host: jinweime.com

cache-control: no-cache

可以看到第一行为请求行,请求方式为get,子路径是?id=2 代表参数id的值为2,http版本为1.1。 后面二行是head区域,第一个请求头是主机地址,第三行也是一个head。get方式的请求参数都是附加的url中所以请求数据部分为空。

post请求报文格式

post /api/feed. http/1.1

accept-encoding: gzip

content-length: 225873

content-ttpe: multipart/form-data; boundary=ocxx3329f....

host: www.myhost.com

connection: keep-alive

--ocxxqfje...

content-dispotition: form-data; name=="username"

content-type: text/plain; charset=utf-8

content-transfer-encoding: 8bit

mrsimple

--cxxii32f..

content-dispotition: form-data; name=="title"

content-type: text/plain; charset=utf-8

content-transfer-encoding: 8bit

test

--ffsaxx......--

这串报代表向 www.myhost.com/api/feed/这个地址发送了一个post请求。 请求的数据格式为 content-type: multipart.form-data,报文有二个参数 username title,username的值为mrsimple。title的值为test。 最后一行是结束行以 -- boundary值 -- 结束, 如果格式不正确服务器将会解析不到的你请求。

响应报文

http响应报文也是由三个部分组成,分别是:状态行 消息head 响应报文,和请求报文的格式十分相似。

可以看到和请求报文相比,只是把第一行的请求行换成了状态行了,状态行提供一个状态码来说明此次请求的资源情况。

http-version status-code reason-phrase crlf

其中的http-version表示服务器http协议的版本,status-code表示服务器响应请求的状态码;reason-phrase表示状态码的文本描述。状态码是一个三位的数字,第一个数字定义了响应的类别。

常见的状态码

200 ok;客户端请求成功

400 bad request:客户端请求有语法错误,服务器不能正确的解析

401 unauthorized;请求未授权

403 forbidden; 服务器收到请求,但是拒绝提供服务

404 not found; 请求的资源不存在, 比如输入了错误的地址;

500 internal server error; 服务器发生了错误

503 server unavailable; 服务器当前不能处理客户端请求

常见的请求头部

content-type: 请求数据的格式

content-length; 消息的长度

host: 请求主机名

user-agent; 发出请求的浏览器类型,可以自定义

accept: 客户端可识别的内容类型

accept-encoding: 客户端可识别的数据编码

connection: 允许客户端和服务器指定请求/响应连接有关的选项,比如设置keep-alive 表示保持连接

android中执行网络请求

android中提供了二种执行网络请求的方式,一种使用 apache的httpclient,另一种java提供的 httpurlconnection。这二种方法都提供了完整的 api, 都很很好的实现对网络的请求功能,但是某些情况下我们需要做取舍分清楚二种方式的区别。

httpclient

android sdk自带了 apache的httpclient,它提供了对http协议的全面支持,可以使用httpclient来执行 http get和http post请求。

httpurlconnection

最佳选择httpurlconnection。二者对比来说,在android 2.2版本之前,httpclient有较少的一些bug,而httpurlconnection一直存在一些让厌烦的bug,比如在对一个可读的inputstream 调用colse()方法时,就有可能导致连接池失败。因此在 android 2.2版本之前使用 httpclient是比较好的选择。 但是在 android2.3及之后 httpurlconnect有了进一步的更新, 它api 简单,体积小,因此非常适用于 android项目中。 httpurlconnection的压缩和缓存机制可以有效的减少网络访问的流量,这块在提升手机省电和流量方面也起来很多的作用。另外在android 6.0中,httpclient以及被移除了,所以以后开发中httpurlconnection是我们唯一的选择了。

使用httpurlconnection请求

fun sendhttpclient(url: string) {

val url =

var conn = url.openconnection() as httpurlconnection

//读取时时间为 2s

conn.readtimeout = 2000

//请求超时时间为 5s

conn.connecttimeout = 5000

//设置请求方式

conn.requestmethod = "post"

//接收输入流

conn.doinput = true

//启动输出流,需要传递参数时需要开启

conn.doinput = true

//添加 header

conn.setrequestproperty("connection", "keep-alive")

//添加请求参数

var paramslist = arraylist()

paramslist.add(basicnamevaluepair("username", "jinwei"))

paramslist.add(basicnamevaluepair("pwd", "pwd.com"))

writeparams(conn.outputstream, paramslist)

//发起请求

conn.connect()

var input = conn.inputstream

//获取结果

var str = convertstreamtostring(input)

log.i(tag, "request data: " str)

input.close()

}

fun writeparams(outpit: outputstream, paramslist: list) {

val paramstr = stringbuffer()

for (value in paramslist) {

if (!textutils.isempty(paramstr)) {

paramstr.append("&")

}

paramstr.append(urlencoder.encode(value.name, "utf-8"))

paramstr.append("=")

paramstr.append(urlencoder.encode(value.value, "utf-8"))

}

var writer = bufferedwriter(outputstreamwriter(outpit, "utf-8"))

//写入参数写入输入流

log.i(tag, paramstr.tostring())

writer.write(paramstr.tostring())

writer.flush()

writer.close()

}

fun convertstreamtostring(input: inputstream): string {

var buffer = bufferedreader(inputstreamreader(input))

var sb = stringbuffer()

var line: string

try {

while (true) {

line = buffer.readline()

if (!textutils.isempty(line)) {

sb.append(line "\n")

} else {

break

}

}

} catch (e: ioexception) {

e.printstacktrace()

}

return sb.tostring()

}

2. volley使用

安静

volley的架构图

架构图

volley是2013年 google i/o大会上推出的一款网络请求相关的框架

它有以下好处

网络请求的自动调度。

多个并发网络连接。

具有标准http缓存一致性的透明磁盘和内存响应缓存。

支持请求优先级。

取消请求api。可以取消单个请求,也可以设置要取消的请求的块或范围。

自定义重试

缺点

不适合数据量过大的传输操作

构建一个stringrequest

一般来说我们一个应用启动后只需要全局获取一个

volley.newrequestqueue(this)实例就够了,这样可以有效的节省系统资源的消耗。

fun sendstringrequest() {

var request = volley.newrequestqueue(this)

var url = "http://baidu.com"

var strrequest = stringrequest(request.method.get, url,

object : response.listener {

override fun onresponse(response: string?) {

log.i(tag, response)

}

},

object : response.errorlistener {

override fun onerrorresponse(error: volleyerror?) {

log.i(tag, "error")

}

})

request.add(strrequest)

}

很简单成功的打印了返回的html数据

jsonrequest

这里我们用的jsonrequest的子类jsonobjectrequest来构建了一个请求,它支持json格式的request和response。

fun sendjsonrequest() {

var request = volley.newrequestqueue(this)

var url = "http://baike.baidu.com/api/openapi/baikelemmacardapi?scope=103&format=json&appid=379020&bk_key=关键字&bk_length=600"

var strrequest = jsonobjectrequest(request.method.post, url, null,

object : response.listener {

override fun onresponse(response: jsonobject?) {

log.i(tag, response.tostring())

}

},

object : response.errorlistener {

override fun onerrorresponse(error: volleyerror?) {

log.i(tag, "error")

}

})

request.add(strrequest)

}

成功的返回了一串json格式的数据

{"id":390935,"sublemmaid":390935,"newlemmaid":7105697,"key".......

imagerequest

volley还支持对图片的获取

fun sendimagerequest() {

var request = volley.newrequestqueue(this)

var url = "https://img-my.csdn.net/uploads/201603/26/1458988468_5804.jpg"

var strrequest = imagerequest(url,

object : response.listener {

override fun onresponse(response: bitmap?) {

findviewbyid(r.id.imageview).setimagebitmap(response)

}

}, 511, 511, bitmap.config.argb_8888,

object : response.errorlistener {

override fun onerrorresponse(error: volleyerror?) {

log.i(tag, "error")

}

})

request.add(strrequest)

}

这段代码成功的bitmap显示到了imageview上面

3. volley源码分析

执行

var request = volley.newrequestqueue(this)

最终会到newrequestqueue方法

public static requestqueue newrequestqueue(context context, basehttpstack stack) {

basicnetwork network;

if (stack == null) {

if (build.version.sdk_int >= 9) {

network = new basicnetwork(new hurlstack());

} else {

// prior to gingerbread, httpurlconnection was unreliable.

// see: http://android-developers.blogspot.com/2011/09/androids-http-clients.html

// at some point in the future we'll move our minsdkversion past froyo and can

// delete this fallback (along with all apache http code).

string useragent = "volley/0";

try {

string packagename = context.getpackagename();

packageinfo info = context.getpackagemanager().getpackageinfo(packagename, 0);

useragent = packagename "/" info.versioncode;

} catch (namenotfoundexception e) {

}

network = new basicnetwork(

new httpclientstack(androidhttpclient.newinstance(useragent)));

}

} else {

network = new basicnetwork(stack);

}

return newrequestqueue(context, network);

}

可以看到代码进入到build.version.sdk_int >= 9的逻辑,network = new basicnetwork(new hurlstack());创建了一个network对象,我们重点关系hrlstack()这个对象,这个对象是最终执行网络请求的地方。

@override

public httpresponse executerequest(request> request, map additionalheaders)

throws ioexception, authfailureerror {

string url = request.get;

// log.i("jinwei"," ## executerequest = " url);

hashmap map = new hashmap<>();

map.putall(request.getheaders());

map.putall(additionalheaders);

if (murlrewriter != null) {

string rewritten = murlrewriter.rewrite;

if (rewritten == null) {

throw new ioexception("url blocked by rewriter: " url);

}

url = rewritten;

}

url parsedurl = new ;

httpurlconnection connection = openconnection(parsedurl, request);

for (string headername : map.keyset()) {

connection.addrequestproperty(headername, map.get(headername));

}

setconnectionparametersforrequest(connection, request);

// initialize httpresponse with data from the httpurlconnection.

int responsecode = connection.getresponsecode();

if (responsecode == -1) {

// -1 is returned by getresponsecode() if the response code could not be retrieved.

// signal to the caller that something was wrong with the connection.

throw new ioexception("could not retrieve response code from httpurlconnection.");

}

if (!hasresponsebody(request.getmethod(), responsecode)) {

return new httpresponse(responsecode, convertheaders(connection.getheaderfields()));

}

return new httpresponse(responsecode, convertheaders(connection.getheaderfields()),

connection.getcontentlength(), inputstreamfromconnection(connection));

}

通过代码可以看到执行网络请求使用的httpurlconnection处理的,具体的调用过程我们继续分析。

newrequestqueue方法最好执行到了return newrequestqueue(context, network);

private static requestqueue newrequestqueue(context context, network network) {

file cachedir = new file(context.getcachedir(), default_cache_dir);

requestqueue queue = new requestqueue(new diskbasedcache(cachedir), network);

queue.start();

return queue;

}

在这里执行了queue.start()方法

public void start() {

stop(); // make sure any currently running dispatchers are stopped.

// create the cache dispatcher and start it.

mcachedispatcher = new cachedispatcher(mcachequeue, mnetworkqueue, mcache, mdelivery);

mcachedispatcher.start();

// create network dispatchers (and corresponding threads) up to the pool size.

log.i("jinwei"," ## mdispatchers.length ## " mdispatchers.length);

for (int i = 0; i < mdispatchers.length; i ) {

networkdispatcher networkdispatcher = new networkdispatcher(mnetworkqueue, mnetwork,

mcache, mdelivery);

mdispatchers[i] = networkdispatcher;

networkdispatcher.start();

}

}

这里总共开启了5个 thread,一个cachethread和四个networkthread。

networkthread的run方法

@override

public void run() {

process.setthreadpriority(process.thread_priority_background);

while (true) {

try {

log.i("jinwei"," ## run ##");

processrequest();

} catch (interruptedexception e) {

// we may have been interrupted because it was time to quit.

log.i("jinwei"," ## mquit ##");

if (mquit) {

return;

}

}

}

}

这里是一个while循环,内部有一个priorityblockingqueue队列take数据,如果返回为null线程就会挂起等待新的队列进来。

重点方法

private void processrequest() throws interruptedexception {

long starttimems = systemclock.elapsedrealtime();

// take a request from the queue.

request> request = mqueue.take();

try {

request.addmarker("network-queue-take");

// if the request was cancelled already, do not perform the

// network request.

if (request.iscanceled()) {

request.finish("network-discard-cancelled");

request.notifylistenerresponsenotusable();

return;

}

addtrafficstatstag(request);

// perform the network request.

networkresponse networkresponse = mnetwork.performrequest(request);

request.addmarker("network-http-complete");

// if the server returned 304 and we delivered a response already,

// we're done -- don't deliver a second identical response.

if (networkresponse.notmodified && request.hashadresponsedelivered()) {

request.finish("not-modified");

request.notifylistenerresponsenotusable();

return;

}

// parse the response here on the worker thread.

response> response = request.parsenetworkresponse(networkresponse);

request.addmarker("network-parse-complete");

// write to cache if applicable.

// todo: only update cache metadata instead of entire record for 304s.

if (request.shouldcache() && response.cacheentry != null) {

mcache.put(request.getcachekey(), response.cacheentry);

request.addmarker("network-cache-written");

}

// post the response back.

request.markdelivered();

mdelivery.postresponse(request, response);

request.notifylistenerresponsereceived(response);

} catch (volleyerror volleyerror) {

volleyerror.setnetworktimems(systemclock.elapsedrealtime() - starttimems);

parseanddelivernetworkerror(request, volleyerror);

request.notifylistenerresponsenotusable();

} catch (exception e) {

volleylog.e(e, "unhandled exception %s", e.tostring());

volleyerror volleyerror = new volleyerror(e);

volleyerror.setnetworktimems(systemclock.elapsedrealtime() - starttimems);

mdelivery.posterror(request, volleyerror);

request.notifylistenerresponsenotusable();

}

}

request> request = mqueue.take()取出之前request.add(strrequest)的数据,如果没有则会一直挂起。

执行这里就会执行到之前hurlstack类中的executerequest方法来通过httpurlconnection来构建一个网络请求了

networkresponse networkresponse = mnetwork.performrequest(request)

源码的简单分析就到这了,具体的设计思路和实现还需要深入研究了。

总结

以上是凯发k8官方网为你收集整理的http请求过程 android,android http网络请求回顾的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

  • 上一篇:
  • 下一篇:
网站地图