我正在尝试将请求标头“Referer”设置为欺骗来自另一个站点的请求。我们需要使用一个特定的referrer的能力测试,它返回一个特定的表单给用户,否则给出一个替代的表单。
我可以通过以下方式在 poltergeist 中做到这一点:
page.driver.headers = {"Referer" => referer_string}
但我找不到 selemium 驱动程序的等效功能。
如何在 capybara selenium 驱动程序中设置请求标头?
我正在尝试将请求标头“Referer”设置为欺骗来自另一个站点的请求。我们需要使用一个特定的referrer的能力测试,它返回一个特定的表单给用户,否则给出一个替代的表单。
我可以通过以下方式在 poltergeist 中做到这一点:
page.driver.headers = {"Referer" => referer_string}
但我找不到 selemium 驱动程序的等效功能。
如何在 capybara selenium 驱动程序中设置请求标头?
Webdriver 不包含执行此操作的 API。有关更多信息,请参阅Selenium tracker 的 issue 141 。这个问题的标题说它是关于响应头的,但决定 Selenium 不会在这个问题的范围内包含用于请求头的 API。添加 API 设置请求标头的几个问题已被标记为重复:第一、第二、第三。
以下是我可以提出的几种可能性:
在大多数情况下,我会选择选项 3。这并不难。
请注意,Ghostdriver 有一个 API,但其他驱动程序不支持它。
对于那些使用 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
我遇到过同样的问题。我解决了它下载 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)
今天有同样的问题,除了我需要为每个测试设置不同的推荐人。我最终使用了一个中间件和一个类来将标头传递给它。以为我会分享(或者也许有更清洁的解决方案?):
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 之外,我还没有使用其他任何东西对其进行过测试,但它应该是透明的,因为在请求实际到达应用程序之前完成了标头注入。
如果您使用的是 javacsript 并且只想在 chrome 上实现,那么Puppeteer是最好的选择,因为它具有修改标头的本机支持。看看这个:https ://pptr.dev/#?product=Puppeteer&version=v10.1.0&show=api-pagesetextrahttpheadersheaders
尽管对于跨浏览器的使用,您可以查看@requestly/selenium
npm 包。它是请求扩展的包装器,可以轻松集成到 selenium- webdriver。扩展可以修改标头。查看:https ://www.npmjs.com/package/@requestly/selenium
我想为 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}
如果使用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 浏览器发出的所有请求上。
直接在 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 以及主要平台。
希望对社区有所帮助。
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.
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);
.
// 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
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.
Now navigate to the required web-application.
driver.get("your-desired-website");
您可以使用 PhantomJSDriver 来完成。
PhantomJSDriver pd = ((PhantomJSDriver) ((WebDriverFacade) getDriver()).getProxiedDriver());
pd.executePhantomJS(
"this.onResourceRequested = function(request, net) {" +
" net.setHeader('header-name', 'header-value')" +
"};");
使用请求对象,您还可以进行过滤,这样就不会为每个请求设置标头。
看看这个: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"')
问题解决了!