如何拦截所有http请求,包括表单提交

Posted

技术标签:

【中文标题】如何拦截所有http请求,包括表单提交【英文标题】:How to intercept all http requests including form submits 【发布时间】:2017-10-04 10:57:15 【问题描述】:

我想拦截从我的网页发出的所有 http 请求,并在请求正文中添加一个参数。我的页面包含表单 - 我还想捕获表单提交。我曾尝试使用 Jquery ajaxSend 和 javascript 的 setRequestHeader,但两者都不适合我。我如何做到这一点?

谢谢

【问题讨论】:

我不认为 Javascript 可以拦截常规的表单提交。您可以捕获提交事件,然后改为使用 AJAX 发送表单。 您可以捕获表单提交并将输入插入到表单中。就 ajax 请求而言,如果您只使用 jquery,全局 ajax 事件就可以工作。没有一种解决方案可以解决问题。 在我的例子中,页面是使用 Apache 速度视图模板生成的——这意味着每个页面都是通过将页面模板与标题模板组合生成的。有很多页面,我希望所有页面都能够向服务器发送令牌。似乎实现这一点的唯一方法似乎是在标头中添加代码以拦截请求。所以建议的解决方案不起作用。有没有其他办法? 也许吧。 Jquery 中的类选择器可能对我有用!谢谢! @lenniekid 您想在请求正文或请求标头中添加参数吗?如果是正文,您可以按照上面的建议添加一个隐藏的表单字段。 【参考方案1】:

https://developer.mozilla.org/en/docs/Web/API/Service_Worker_API

Service Worker 本质上充当位于 Web 应用程序、浏览器和网络(如果可用)之间的代理服务器。

它采用JavaScript文件的形式,可以控制与之关联的网页/站点,拦截和修改导航和资源请求

您通过以下方式在您的应用程序代码中注册一个服务工作者,例如,sw.js

if ('serviceWorker' in navigator) 
  window.addEventListener('load', function() 
    navigator.serviceWorker.register('sw.js').then(function(registration) 
      console.log('Service worker registered with scope: ', registration.scope);
    , function(err) 
      console.log('ServiceWorker registration failed: ', err);
    );
  );

sw.js 文件中(实际的 service-worker 代码):要拦截请求,您将 fetch 事件侦听器附加到调用 respondWith() 方法并使用 .request 执行某些操作的 service worker来自事件对象的成员:

self.addEventListener('fetch', function(event) 
  event.respondWith(
    // intercept requests by handling event.request here
  );
);

一个简单的服务工作者,只是通过请求不变看起来像这样:

self.addEventListener('fetch', function(event) 
  event.respondWith(
    fetch(event.request)
  );
);

要将参数添加到请求正文中,您需要:

    序列化请求。 修改该序列化请求。 反序列化修改后的请求以创建新请求。 致电fetch(…) 提出新请求。

所以,一个服务工作者会做所有看起来像这样的事情(未经测试):

self.addEventListener('fetch', function(event) 
  event.respondWith(
    fetchWithParamAddedToRequestBody(event.request)
  );
);
function fetchWithParamAddedToRequestBody(request) 
  serialize(request).then(function(serialized) 
    // modify serialized.body here to add your request parameter
    deserialize(serialized).then(function(request) 
      return fetch(request);
    );
  ); // fixed this

function serialize(request) 
  var headers = ;
  for (var entry of request.headers.entries()) 
    headers[entry[0]] = entry[1];
  
  var serialized = 
    url: request.url,
    headers: headers,
    method: request.method,
    mode: request.mode,
    credentials: request.credentials,
    cache: request.cache,
    redirect: request.redirect,
    referrer: request.referrer
  ;  
  if (request.method !== 'GET' && request.method !== 'HEAD') 
    return request.clone().text().then(function(body) 
      serialized.body = body;
      return Promise.resolve(serialized);
    );
  
  return Promise.resolve(serialized);

function deserialize(data) 
  return Promise.resolve(new Request(data.url, data));

注意:https://serviceworke.rs/request-deferrer_service-worker_doc.html,来自Service Worker Cookbook 的页面,是我从serialize(…) 代码/方法中提取的地方——通过https://***.com/questions/35420980/how-to-alter-the-headers-of-a-request/35421644#35421644—and 的答案,值得一试看一下,因为那里的代码有详细的注释解释它在做什么

【讨论】:

这太酷了,我有我需要的东西来解决我的问题。下一秒我检查了this 和最亲爱的 - IE 和 Edge :) 上帝保佑他们 Service Worker 是 Web Worker 的别称还是不同? 在带有 iframe 的页面中触发时是否跟踪 api 调用?如果调用到其他域(sso)并返回到同一个域(它是否也拦截了那个 api?)【参考方案2】:

试试这个代码:

(function(send) 

XMLHttpRequest.prototype.send = function(data) 

    var _valuToAdd = $("input[name='valuToAdd']").val();
    this.setRequestHeader('valueName', _valuToAdd);
    send.call(this, data);
;
)(XMLHttpRequest.prototype.send);

【讨论】:

不拦截表单提交。 这不是拦截简单的获取请求。

以上是关于如何拦截所有http请求,包括表单提交的主要内容,如果未能解决你的问题,请参考以下文章

restful有几种请求,表单如何提交put请求

jQuery拦截表单提交到参数字符串

HTTP(“跨域问题”和“防止表单重复提交”)

拦截器springmvc防止表单重复提交

如何区分从 HTML 表单提交的 HTTP 请求和从客户端提交的 HTTP 请求?

Struts2系列:(13)防表单重复提交(token + 拦截器)