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)
源码的简单分析就到这了,具体的设计思路和实现还需要深入研究了。
总结
以上是尊龙游戏旗舰厅官网为你收集整理的http请求过程 android,android http网络请求回顾的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇:
- 下一篇: