zhllxt/asio2

http 请求拦截器before获取不到url

famik opened this issue · 10 comments

famik commented
struct aop_log
{
	bool before(http::request& req, http::response& rep)
	{
		asio2::detail::ignore_unused(rep);
		//printf("aop_log before %s\n", req.method_string().data());
                 printf("url: %s\n", req.url().get_path().data());  // 打印出来是空的
		return true;
	}
};
zhllxt commented

你用的应该是较早的版本了,现在新的版本为了兼容boost,类型已经改了,像下面这样:

bool before(http::web_request& req, http::web_response& rep)

但是不管是老版本的,还是新版本的,实际上目前在http_server中这个web_request并没有填充url,所以是空的。

这个url是用在http client里的:

std::string_view url = R"(http://www.baidu.com/cond?json={"qeury":"name like '%abc%'","id":1})";
http::web_request req = http::make_request(url);
asio2::http_client::execute(req);

此时web_request里面保存了url信息,可以获取到url的各种参数信息。

http server 端基本上通过web_request.target()就能获取到http请求的后面那部分的url,就是请求的target,不过你这个用法到是也有意义,意义就是接口比较统一,我考虑考虑后面要不要加上这个功能,因为加这个功能还需要再拼接url,http收到请求的时候只有target,还要查询出host port等,再拼接成一个完整的url才准确。

famik commented

发Issues的时候从README.md拷过来改的,没注意看是老版本的代码,实际上我在项目中用的是新版本

我是想把请求和响应的日志在拦截器中统一打印出来

famik commented

取 target() 可以
我想在after把web_response的status和body打印出来,好像也不行

zhllxt commented

取 target() 可以 我想在after把web_response的status和body打印出来,好像也不行

rep.result(); 就是取status
response的body通常是打印不了的,因为body分两种:字符串和文件;

	server.bind("/", [](http::web_request& req, http::web_response& rep)
	{
		rep.fill_file(req.target());
	}, aop_check{}, http::enable_cache);

像上面这段代码,收到的http请求的target通常是/index.html这种,因此通过调用rep.fill_file函数直接设置了一个文件并响应给客户端,此时rep.body()的内部实际上是个文件句柄,且内部没有做对这个文件句柄的打印操作,无法打印。

如果不是调用的rep.fill_file,而是调用的rep.fill_json这种,向客户端返回一段json内容,那么rep.body()的内部实际上就是一个字符串,此时是可以直接打印的,std::cout << rep.body(); 即可,或者用rep.body().text();可以取出字符串的内容。

famik commented

取 target() 可以 我想在after把web_response的status和body打印出来,好像也不行

rep.result(); 就是取status response的body通常是打印不了的,因为body分两种:字符串和文件;

	server.bind("/", [](http::web_request& req, http::web_response& rep)
	{
		rep.fill_file(req.target());
	}, aop_check{}, http::enable_cache);

像上面这段代码,收到的http请求的target通常是/index.html这种,因此通过调用rep.fill_file函数直接设置了一个文件并响应给客户端,此时rep.body()的内部实际上是个文件句柄,且内部没有做对这个文件句柄的打印操作,无法打印。

如果不是调用的rep.fill_file,而是调用的rep.fill_json这种,向客户端返回一段json内容,那么rep.body()的内部实际上就是一个字符串,此时是可以直接打印的,std::cout << rep.body(); 即可,或者用rep.body().text();可以取出字符串的内容。

问题是在拦截器的after函数里打印rep.result()出来一直是0

body是不是字符串可以通过Content-Type来判断

zhllxt commented

流程:

  1. before
  2. server.bind(...) 的监听函数
  3. after
    你是不是在bind(...)中没有给rep的status赋值?如果没有的话,你在after中打印出来的值就是0。
    如果你调用的是rep.fill_file file_json这些函数,他已经自动给status赋值为ok了。
    如果你没有调用这些函数,自己给rep填充的内容,那你需要自己给status赋值。
    如此:rep.result(http::status::ok);
famik commented

流程:

  1. before
  2. server.bind(...) 的监听函数
  3. after
    你是不是在bind(...)中没有给rep的status赋值?如果没有的话,你在after中打印出来的值就是0。
    如果你调用的是rep.fill_file file_json这些函数,他已经自动给status赋值为ok了。
    如果你没有调用这些函数,自己给rep填充的内容,那你需要自己给status赋值。
    如此:rep.result(http::status::ok);

是用fill_json的,发现是用 rep.defer() 延迟给rep填充的在拦截器after取不到

zhllxt commented

是用fill_json的,发现是用 rep.defer() 延迟给rep填充的在拦截器after取不到

对哦,是有这个问题,我得思考思考,要不要调整。

zhllxt commented

流程:

  1. before
  2. server.bind(...) 的监听函数
  3. after
    你是不是在bind(...)中没有给rep的status赋值?如果没有的话,你在after中打印出来的值就是0。
    如果你调用的是rep.fill_file file_json这些函数,他已经自动给status赋值为ok了。
    如果你没有调用这些函数,自己给rep填充的内容,那你需要自己给status赋值。
    如此:rep.result(http::status::ok);

是用fill_json的,发现是用 rep.defer() 延迟给rep填充的在拦截器after取不到

已经修复了这个问题,在develop分支最新代码。

zhllxt commented

流程:

  1. before
  2. server.bind(...) 的监听函数
  3. after
    你是不是在bind(...)中没有给rep的status赋值?如果没有的话,你在after中打印出来的值就是0。
    如果你调用的是rep.fill_file file_json这些函数,他已经自动给status赋值为ok了。
    如果你没有调用这些函数,自己给rep填充的内容,那你需要自己给status赋值。
    如此:rep.result(http::status::ok);

是用fill_json的,发现是用 rep.defer() 延迟给rep填充的在拦截器after取不到

已经修复了这个问题,在develop分支最新代码。

再次修复一个问题:当rep.defer()不是在io_context线程中析构时,会导致after没有在io_context线程中调用的问题。理论上before,bind(...),after都应在io_context线程中被调用。

printf("url: %s\n", req.url().get_path().data()); // 打印出来是空的

此问题也已修复。req.url().get_path(); req.url().get_query(); req.url().get_target(); 等现在均可正常调用
但无法获取client请求的完整URL,如想通过req.url().string()来得到http://yourdomain.com/index.html这种,是得不到的,且难以解决,因为client可能使用的是域名,此时服务端的before after函数中只能获取到服务端监听的地址,无法获取域名,如果从Host头中获取域名并不可靠。