69

我正在尝试将请求标头“Referer”设置为欺骗来自另一个站点的请求。我们需要使用一个特定的referrer的能力测试,它返回一个特定的表单给用户,否则给出一个替代的表单。

我可以通过以下方式在 poltergeist 中做到这一点:

page.driver.headers = {"Referer" => referer_string}

但我找不到 selemium 驱动程序的等效功能。

如何在 capybara selenium 驱动程序中设置请求标头?

4

11 回答 11

49

Webdriver 不包含执行此操作的 API。有关更多信息,请参阅Selenium tracker 的 issue 141 。这个问题的标题说它是关于响应头的,但决定 Selenium 不会在这个问题的范围内包含用于请求头的 API。添加 API 设置请求标头的几个问题已被标记为重复:第一第二第三

以下是我可以提出的几种可能性:

  1. 使用另一个驱动程序/库而不是 selenium
  2. 编写一个特定于浏览器的插件(或查找现有插件),允许您为请求添加标头。
  3. 使用browsermob-proxy或其他一些代理。

在大多数情况下,我会选择选项 3。这并不难。

请注意,Ghostdriver 有一个 API,但其他驱动程序不支持它。

于 2013-03-26T20:51:07.407 回答
33

对于那些使用 Python 的人,您可以考虑使用Selenium Wire,它可以设置请求标头并为您提供检查请求和响应的能力。

from seleniumwire import webdriver  # Import from seleniumwire

# Create a new instance of the Chrome driver (or Firefox)
driver = webdriver.Chrome()

# Create a request interceptor
def interceptor(request):
    del request.headers['Referer']  # Delete the header first
    request.headers['Referer'] = 'some_referer'

# Set the interceptor on the driver
driver.request_interceptor = interceptor

# All requests will now use 'some_referer' for the referer
driver.get('https://mysite')

安装:

pip install selenium-wire
于 2018-08-19T15:44:29.250 回答
9

我遇到过同样的问题。我解决了它下载 modify-headers firefox 插件并用 selenium 激活它。

python中的代码如下

fp = webdriver.FirefoxProfile()
path_modify_header = 'C:/xxxxxxx/modify_headers-0.7.1.1-fx.xpi'
fp.add_extension(path_modify_header)

fp.set_preference("modifyheaders.headers.count", 1)
fp.set_preference("modifyheaders.headers.action0", "Add")
fp.set_preference("modifyheaders.headers.name0", "Name_of_header") # Set here the name of the header
fp.set_preference("modifyheaders.headers.value0", "value_of_header") # Set here the value of the header
fp.set_preference("modifyheaders.headers.enabled0", True)
fp.set_preference("modifyheaders.config.active", True)
fp.set_preference("modifyheaders.config.alwaysOn", True)

driver = webdriver.Firefox(firefox_profile=fp)
于 2017-01-06T20:54:15.883 回答
4

今天有同样的问题,除了我需要为每个测试设置不同的推荐人。我最终使用了一个中间件和一个类来将标头传递给它。以为我会分享(或者也许有更清洁的解决方案?):

lib/request_headers.rb:

class CustomHeadersHelper
  cattr_accessor :headers
end

class RequestHeaders
  def initialize(app, helper = nil)
    @app, @helper = app, helper
  end

  def call(env)
    if @helper
      headers = @helper.headers

      if headers.is_a?(Hash)
        headers.each do |k,v|
          env["HTTP_#{k.upcase.gsub("-", "_")}"] = v
        end
      end
    end

    @app.call(env)
  end
end

config/initializers/middleware.rb

require 'request_headers'

if %w(test cucumber).include?(Rails.env)
  Rails.application.config.middleware.insert_before Rack::Lock, "RequestHeaders", CustomHeadersHelper
end

spec/support/capybara_headers.rb

require 'request_headers'

module CapybaraHeaderHelpers
  shared_context "navigating within the site" do
    before(:each) { add_headers("Referer" => Capybara.app_host + "/") }
  end

  def add_headers(custom_headers)
    if Capybara.current_driver == :rack_test
      custom_headers.each do |name, value|
        page.driver.browser.header(name, value)
      end
    else
      CustomHeadersHelper.headers = custom_headers
    end
  end
end

spec/spec_helper.rb

...
config.include CapybaraHeaderHelpers

然后我可以在任何需要的地方包含共享上下文,或者在另一个before块中传递不同的标题。除了 Selenium 和 RackTest 之外,我还没有使用其他任何东西对其进行过测试,但它应该是透明的,因为在请求实际到达应用程序之前完成了标头注入。

于 2013-06-19T17:46:22.760 回答
2

如果您使用的是 javacsript 并且只想在 chrome 上实现,那么Puppeteer是最好的选择,因为它具有修改标头的本机支持。看看这个:https ://pptr.dev/#?product=Puppeteer&version=v10.1.0&show=api-pagesetextrahttpheadersheaders

尽管对于跨浏览器的使用,您可以查看@requestly/seleniumnpm 包。它是请求扩展的包装器,可以轻松集成到 selenium- webdriver。扩展可以修改标头。查看:https ://www.npmjs.com/package/@requestly/selenium

于 2021-07-24T21:06:53.157 回答
2

我想为 RSpec/Ruby 提供一些更精简的东西,以便自定义代码只需要放在一个地方。这是我的解决方案:

/spec/support/selenium.rb
...
RSpec.configure do |config|
  config.after(:suite) do
    $custom_headers = nil
  end
end

module RequestWithExtraHeaders
  def headers
    $custom_headers.each do |key, value|
      self.set_header "HTTP_#{key}", value
    end if $custom_headers

    super
  end
end
class ActionDispatch::Request
  prepend RequestWithExtraHeaders
end

然后在我的规格中:

/specs/features/something_spec.rb
...
$custom_headers = {"Referer" => referer_string}
于 2019-06-04T15:10:12.523 回答
1

如果使用HtmlUnitDriver,则可以通过修改 来设置请求标头WebClient,如下所示:

final case class Header(name: String, value: String)

final class HtmlUnitDriverWithHeaders(headers: Seq[Header]) extends HtmlUnitDriver {
  super.modifyWebClient {
    val client = super.getWebClient
    headers.foreach(h => client.addRequestHeader(h.name, h.value))
    client
  }
}

然后,标头将出现在 Web 浏览器发出的所有请求上。

于 2017-03-23T18:09:31.520 回答
1

直接在 Web 驱动程序中设置请求标头不起作用。这是真实的。

但是,您可以通过使用浏览器 devtools (我使用 edge 和 chrome 进行测试)来解决这个问题,并且效果很好。

根据文档,您可以添加自定义标头: https ://chromedevtools.github.io/devtools-protocol/tot/Network/

请在下面找到一个示例。

    [Test]
    public async Task AuthenticatedRequest()
    {
        await LogMessage("=== starting the test ===");

        EdgeOptions options = new EdgeOptions {UseChromium = true};
        options.AddArgument("no-sandbox");
        var driver = new RemoteWebDriver(new Uri(_testsSettings.GridUrl), options.ToCapabilities(), TimeSpan.FromMinutes(3));

        //Get DevTools
        IDevTools devTools = driver;

        //DevTools Session
        var session = devTools.GetDevToolsSession();

        var devToolsSession = session.GetVersionSpecificDomains<DevToolsSessionDomains>();
        await devToolsSession.Network.Enable(new Network.EnableCommandSettings());
        
        var extraHeader = new Network.Headers();
        var data = await Base64KerberosTicket();
        var headerValue = $"Negotiate {data}";
        
        await LogMessage($"header values is {headerValue}");

        extraHeader.Add("Authorization", headerValue);
        await devToolsSession.Network.SetExtraHTTPHeaders(new Network.SetExtraHTTPHeadersCommandSettings
        {
            Headers = extraHeader
        });

        driver.Url = _testsSettings.TestUrl;

        driver.Navigate();
        driver.Quit();

        await LogMessage("=== ending the test ===");
    }

这是一个用 C# 编写的示例,但同样适用于 java、python 以及主要平台。

希望对社区有所帮助。

于 2021-10-06T10:55:38.580 回答
1

With the solutions already discussed above the most reliable one is using Browsermob-Proxy

But while working with the remote grid machine, Browsermob-proxy isn't really helpful.

This is how I fixed the problem in my case. Hopefully, might be helpful for anyone with a similar setup.

  1. Add the ModHeader extension to the chrome browser

How to download the Modheader? Link

ChromeOptions options = new ChromeOptions();
options.addExtensions(new File(C://Downloads//modheader//modheader.crx));

// Set the Desired capabilities 
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(ChromeOptions.CAPABILITY, options);

// Instantiate the chrome driver with capabilities
WebDriver driver = new RemoteWebDriver(new URL(YOUR_HUB_URL), options);
  1. Go to the browser extensions and capture the Local Storage context ID of the ModHeader

Capture ID from ModHeader

  1. Navigate to the URL of the ModHeader to set the Local Storage Context

.

// set the context on the extension so the localStorage can be accessed
driver.get("chrome-extension://idgpnmonknjnojddfkpgkljpfnnfcklj/_generated_background_page.html");

Where `idgpnmonknjnojddfkpgkljpfnnfcklj` is the value captured from the Step# 2
  1. Now add the headers to the request using Javascript

.

   ((Javascript)driver).executeScript(
         "localStorage.setItem('profiles', JSON.stringify([{  title: 'Selenium', hideComment: true, appendMode: '', 
             headers: [                        
               {enabled: true, name: 'token-1', value: 'value-1', comment: ''},
               {enabled: true, name: 'token-2', value: 'value-2', comment: ''}
             ],                          
             respHeaders: [],
             filters: []
          }]));");

Where token-1, value-1, token-2, value-2 are the request headers and values that are to be added.

  1. Now navigate to the required web-application.

    driver.get("your-desired-website");

于 2020-06-17T10:54:52.353 回答
-1

您可以使用 PhantomJSDriver 来完成。

PhantomJSDriver pd = ((PhantomJSDriver) ((WebDriverFacade) getDriver()).getProxiedDriver());
pd.executePhantomJS(
            "this.onResourceRequested = function(request, net) {" +
            "   net.setHeader('header-name', 'header-value')" +
            "};");

使用请求对象,您还可以进行过滤,这样就不会为每个请求设置标头。

于 2017-12-22T13:11:29.123 回答
-2

看看这个:chrome_options = Options()

chrome_options.add_argument('--headless')
chrome_options.add_argument('user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36"')

问题解决了!

于 2019-05-04T05:41:49.450 回答