从jsonRpc接入http请求直至开始业务逻辑处理总体层级如下:

JsonServiceExporter->handleRequest-> handle -> handleRequest0 ->handleRequest -> handleJsonNodeRequest -> handleObject -> methodInvoke

  • google的jsonrpc4j通过实现springframework中的httpRequestHandler来对请求进行处理;源码如下:
package com.googlecode.jsonrpc4j.spring;import com.googlecode.jsonrpc4j.JsonRpcServer;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.HttpRequestHandler;class JsonServiceExporter extends AbstractJsonServiceExporter implements HttpRequestHandler {private JsonRpcServer jsonRpcServer;JsonServiceExporter() {}protected void exportService() {this.jsonRpcServer = this.getJsonRpcServer();}public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.jsonRpcServer.handle(request, response);response.getOutputStream().flush();}
}
  • 进入handle可以看到在此层会对捕获http请求中出现的所有异常,并进行异常处理,回显jsonrpc中自定义的错误代码以及结构;源码如下:

/*** Handles a servlet request.** @param request  the {@link HttpServletRequest}* @param response the {@link HttpServletResponse}* @throws IOException on error*/
public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException {logger.debug("Handling HttpServletRequest {}", request);response.setContentType(contentType);OutputStream output = response.getOutputStream();InputStream input = getRequestStream(request);int result = ErrorResolver.JsonError.PARSE_ERROR.code;int contentLength = 0;ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();try {String acceptEncoding = request.getHeader(ACCEPT_ENCODING);result = handleRequest0(input, output, acceptEncoding, response, byteOutput);contentLength = byteOutput.size();} catch (Throwable t) {if (StreamEndedException.class.isInstance(t)) {logger.debug("Bad request: empty contents!");} else {logger.error(t.getMessage(), t);}}int httpStatusCode = httpStatusCodeProvider == null ? DefaultHttpStatusCodeProvider.INSTANCE.getHttpStatusCode(result): httpStatusCodeProvider.getHttpStatusCode(result);response.setStatus(httpStatusCode);response.setContentLength(contentLength);byteOutput.writeTo(output);output.flush();
}
  • 进入handleRequest0 ->handleRequest -> handleJsonNodeRequest,这一步从输入流中读取对应的请求并归属为jsonrpc请求、处理对应请求,并返回结果代码;源码如下:
/*** Handles a single request from the given {@link InputStream},* that is to say that a single {@link JsonNode} is read from* the stream and treated as a JSON-RPC request.  All responses* are written to the given {@link OutputStream}.** @param input  the {@link InputStream}* @param output the {@link OutputStream}* @return the error code, or {@code 0} if none* @throws IOException on error*/
public int handleRequest(final InputStream input, final OutputStream output) throws IOException {final ReadContext readContext = ReadContext.getReadContext(input, mapper);try {readContext.assertReadable();final JsonNode jsonNode = readContext.nextValue();for (JsonRpcInterceptor interceptor : interceptorList) {interceptor.preHandleJson(jsonNode);}JsonResponse jsonResponse = handleJsonNodeRequest(jsonNode);writeAndFlushValue(output, jsonResponse.getResponse());if (jsonResponse.getExceptionToRethrow() != null) {throw jsonResponse.getExceptionToRethrow();}return jsonResponse.getCode();} catch (JsonParseException | JsonMappingException e) {JsonResponse responseError = createResponseError(VERSION, NULL, JsonError.PARSE_ERROR);writeAndFlushValue(output, responseError.getResponse());return responseError.getCode();}
}
  • 进入handleJsonNodeRequest,这里会对请求体中的json对象进行判别并进行对应处理;源码如下:
/*** Handles the given {@link JsonNode} and creates {@link JsonResponse}** @param node the {@link JsonNode}* @return the {@link JsonResponse} instance*/
protected JsonResponse handleJsonNodeRequest(final JsonNode node)throws JsonParseException, JsonMappingException {if (node.isArray()) {return handleArray((ArrayNode) node);}if (node.isObject()) {return handleObject((ObjectNode) node);}return createResponseError(VERSION, NULL, JsonError.INVALID_REQUEST);
}
REQUEST);}
  • 这里以handleObject为例,进来后其实就是对json的结构进行验证并调用对应方法;部分解析我会写道下面源码里边;
/*** Handles the given {@link ObjectNode} and creates {@link JsonResponse}** @param node   the {@link JsonNode}* @return the {@link JsonResponse} instance*/private JsonResponse handleObject(final ObjectNode node)throws JsonParseException, JsonMappingException {logger.debug("Request: {}", node);// 验证请求中是否存在"jsonRpc" 以及 "method"if (!isValidRequest(node)) {return createResponseError(VERSION, NULL, JsonError.INVALID_REQUEST);}// 获取对应请求idObject id = parseId(node.get(ID));// 验证参数是否为空String jsonRpc = hasNonNullData(node, JSONRPC) ? node.get(JSONRPC).asText() : VERSION;if (!hasNonNullData(node, METHOD)) {return createResponseError(jsonRpc, id, JsonError.METHOD_NOT_FOUND);}// 获取方法路径信息final String fullMethodName = node.get(METHOD).asText();final String partialMethodName = getMethodName(fullMethodName);final String serviceName = getServiceName(fullMethodName);Set<Method> methods = findCandidateMethods(getHandlerInterfaces(serviceName), partialMethodName);if (methods.isEmpty()) {return createResponseError(jsonRpc, id, JsonError.METHOD_NOT_FOUND);}// 验证方法参数是否齐全AMethodWithItsArgs methodArgs = findBestMethodByParamsNode(methods, node.get(PARAMS));if (methodArgs == null) {return createResponseError(jsonRpc, id, JsonError.METHOD_PARAMS_INVALID);}try (InvokeListenerHandler handler = new InvokeListenerHandler(methodArgs, invocationListener)) {try {// 若设置预处理拦截器则会在此处拦截请求if (this.requestInterceptor != null) {this.requestInterceptor.interceptRequest(node);}// serviceName 其实就是我们通过@JsonRpcService设置的层级,在程序启动时会自动加载到内存当中Object target = getHandler(serviceName);// interceptors preHandlefor (JsonRpcInterceptor interceptor : interceptorList) {interceptor.preHandle(target, methodArgs.method, methodArgs.arguments);}// invocation 做内部方法调用执行业务逻辑JsonNode result = invoke(target, methodArgs.method, methodArgs.arguments);handler.result = result;// interceptors postHandle 若设置post拦截器则会在此处拦截请求for (JsonRpcInterceptor interceptor : interceptorList) {interceptor.postHandle(target, methodArgs.method, methodArgs.arguments, result);}// 验证id不为空if (!isNotificationRequest(id)) {return createResponseSuccess(jsonRpc, id, handler.result);}return new JsonResponse(null, JsonError.OK.code);} catch (JsonParseException | JsonMappingException e) {throw e; // rethrow this, it will be handled as PARSE_ERROR later} catch (Throwable e) {handler.error = e;return handleError(id, jsonRpc, methodArgs, e);}}}

JsonRpc源码--处理http请求源码刨析相关推荐

  1. HTTP状态码、接口请求状态码

    HTTP状态码是由三位数字组成的数字代码,用于表示HTTP协议处理请求时的返回状态.状态码通常由服务端发送,客户端通过接收状态码来了解请求是否成功,以及出现错误时出错的原因. 以下是HTTP状态码的详 ...

  2. Tomcat 处理 HTTP 请求源码分析(下)【转】

    原文地址:https://www.infoq.cn/article/zh-tomcat-http-request-2 很多开源应用服务器都是集成 tomcat 作为 web container 的,而 ...

  3. Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR 请求头

    本实验操作系统选用 CentOS release 5.6 (Final) 实验目的实现 Squid 代理服务器 编译源码 伪造HTTP_X_FORWARDED_FOR  请求头 .使其显示任意IP 过 ...

  4. Okhttp同步请求源码分析

    进阶android,OKhttp源码分析--同步请求的源码分析 OKhttp是我们经常用到的框架,作为开发者们,我们不单单要学会灵活使用,还要知道他的源码是如何设计的. 今天我们来分析一下OKhttp ...

  5. Spring源码解析 -- SpringWeb请求参数获取解析

    Spring源码解析 – SpringWeb请求参数获取解析 简介 在文章:Spring Web 请求初探中,我们看到最后方法反射调用的相关代码,本篇文章就探索其中的参数是如何从请求中获取的 概览 方 ...

  6. Spring源码解析 -- SpringWeb请求映射Map初始化

    简介 在上篇文章中,大致解析了Spring如何将请求路径与处理方法进行映射,但映射相关的初始化对于我们来说还是一团迷雾 本篇文章就来探索下,请求路径和处理方法的映射,是如何进行初始化的 概览 基于上篇 ...

  7. Spring 源码解析 -- SpringWeb请求映射解析

    Spring 源码解析 – SpringWeb请求映射解析 简介 基于上篇请求路径初步探索,了解到了一个请求到具体处理方法的大致路径,本篇就继续探索,看下路径是如何匹配到处理方法的 概览 基于上篇:S ...

  8. RocketMQ源码(十七)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码

    转载来源: RocketMQ源码(19)-Broker处理DefaultMQPushConsumer发起的拉取消息请求源码[一万字]_刘Java的博客-CSDN博客 此前我们学习了RocketMQ源码 ...

  9. RocketMQ源码(19)—Broker处理DefaultMQPushConsumer发起的拉取消息请求源码【一万字】

    基于RocketMQ release-4.9.3,深入的介绍了Broker处理DefaultMQPushConsumer发起的拉取消息请求源码. 此前我们学习了RocketMQ源码(18)-Defau ...

最新文章

  1. [Vue.js进阶]从源码角度剖析vue-router(三)
  2. 构设计杂谈004——架构师
  3. JavaScript快速上手入门
  4. 【分解质因数】【树状数组】【快速幂】codeforces 2014 ACM-ICPC Vietnam National Second Round E. ACM...
  5. oracle大批量数据统计,加速Oracle大批量数据处理的2个好用方案
  6. Redis Cluster搭建方法简介22211111
  7. 交换机的基本配置实验报告_无线网络设计配置即实验报告
  8. EPSnbsp;QOS体系图的解读
  9. postgresql开启历史查询记录日志
  10. ubnt路由器虚拟服务器,UBNT UAP系列 Wi-Fi设置教程 装修必看
  11. Android手机HC-05蓝牙连接Arduino nano获取DHT-11温湿度传感器数据
  12. uniapp获取云服务空间 数据
  13. 10 个Web3 设计灵感网站
  14. SIPWeb视频对讲,群呼,广播会议一体方案分析
  15. 曹雪芹诗歌中的鸿蒙,曹雪芹的诗词丢失,红楼梦里的诗句
  16. 进程和线程的区别,进程间通信方式,怎么选择比较好
  17. 在互联网上班是什么感觉?
  18. 不懂SEO该如何做搜索引擎优化?
  19. 复杂网络分析工具总结
  20. 1.3编程实现从键盘依次输入姓名(字符串)、年龄(整型)、性别(字符)和成绩(浮点型),然后依次显示上述内容

热门文章

  1. c语言函数详解1——自定义函数
  2. html+css+php+mysql实现注册+登录+修改密码(附完整代码)
  3. 老罗笔记人工智能文字处理软件 Rogabet Notepad v1.5-2023-616
  4. 艾美捷Cas9 ELISA检测试剂盒的制备和文献参考
  5. MySQL8.0远程连接和用户授权相关设置
  6. 2017暑假集训总结
  7. 【山东】泰安联想X3850X6 X6服务器维修记录
  8. 通过anaconda下载pytorch
  9. python博客园_用Python向博客园发布新文章
  10. 手游云测试工具TestBird登陆韩国